⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udp.c

📁 An implementation of the TCP/IP protocol suite for the LINUX operating system. INET is implemented u
💻 C
📖 第 1 页 / 共 2 页
字号:
325                 return err;
326         memcpy_fromfs(&sin, usin, sizeof(sin));
327         if (sin.sin_family && sin.sin_family != AF_INET) 
328                 return(-EINVAL);
329         if (sin.sin_port == 0) 
330                 return(-EINVAL);
331   } else {
332         if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
333         sin.sin_family = AF_INET;
334         sin.sin_port = sk->dummy_th.dest;
335         sin.sin_addr.s_addr = sk->daddr;
336   }
337   
338   if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
339         return -EACCES;                 /* Must turn broadcast on first */
340   sk->inuse = 1;
341 
342   /* Send the packet. */
343   tmp = udp_send(sk, &sin, from, len);
344 
345   /* The datagram has been sent off.  Release the socket. */
346   release_sock(sk);
347   return(tmp);
348 }
349 
350 
351 static int
352 udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
353           unsigned flags)
354 {
355   return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
356 }
357 
358 
359 int
360 udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
361 {
362   int err;
363   switch(cmd) {
364         case DDIOCSDBG:
365                 {
366                         int val;
367 
368                         if (!suser()) return(-EPERM);
369                         err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
370                         if(err)
371                                 return err;
372                         val = get_fs_long((int *)arg);
373                         switch(val) {
374                                 case 0:
375                                         inet_debug = 0;
376                                         break;
377                                 case 1:
378                                         inet_debug = DBG_UDP;
379                                         break;
380                                 default:
381                                         return(-EINVAL);
382                         }
383                 }
384                 break;
385         case TIOCOUTQ:
386                 {
387                         unsigned long amount;
388 
389                         if (sk->state == TCP_LISTEN) return(-EINVAL);
390                         amount = sk->prot->wspace(sk)/*/2*/;
391                         err=verify_area(VERIFY_WRITE,(void *)arg,
392                                         sizeof(unsigned long));
393                         if(err)
394                                 return(err);
395                         put_fs_long(amount,(unsigned long *)arg);
396                         return(0);
397                 }
398 
399         case TIOCINQ:
400                 {
401                         struct sk_buff *skb;
402                         unsigned long amount;
403 
404                         if (sk->state == TCP_LISTEN) return(-EINVAL);
405                         amount = 0;
406                         skb = sk->rqueue;
407                         if (skb != NULL) {
408                                 /*
409                                  * We will only return the amount
410                                  * of this packet since that is all
411                                  * that will be read.
412                                  */
413                                 amount = skb->len;
414                         }
415                         err=verify_area(VERIFY_WRITE,(void *)arg,
416                                                 sizeof(unsigned long));
417                         if(err)
418                                 return(err);
419                         put_fs_long(amount,(unsigned long *)arg);
420                         return(0);
421                 }
422 
423         default:
424                 return(-EINVAL);
425   }
426   return(0);
427 }
428 
429 
430 /*
431  * This should be easy, if there is something there we\
432  * return it, otherwise we block.
433  */
434 int
435 udp_recvfrom(struct sock *sk, unsigned char *to, int len,
436              int noblock, unsigned flags, struct sockaddr_in *sin,
437              int *addr_len)
438 {
439   int copied = 0;
440   struct sk_buff *skb;
441   int er;
442 
443 
444   /*
445    * This will pick up errors that occured while the program
446    * was doing something else.
447    */
448   if (sk->err) {
449         int err;
450 
451         err = -sk->err;
452         sk->err = 0;
453         return(err);
454   }
455 
456   if (len == 0) 
457         return(0);
458   if (len < 0) 
459         return(-EINVAL);
460 
461   if (addr_len) {
462         er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
463         if(er)
464                 return(er);
465         put_fs_long(sizeof(*sin), addr_len);
466   }
467   if(sin)
468   {
469         er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
470         if(er)
471                 return(er);
472   }
473   er=verify_area(VERIFY_WRITE,to,len);
474   if(er)
475         return er;
476   skb=skb_recv_datagram(sk,flags,noblock,&er);
477   if(skb==NULL)
478         return er;
479   copied = min(len, skb->len);
480 
481   /* FIXME : should use udp header size info value */
482   skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
483 
484   /* Copy the address. */
485   if (sin) {
486         struct sockaddr_in addr;
487 
488         addr.sin_family = AF_INET;
489         addr.sin_port = skb->h.uh->source;
490         addr.sin_addr.s_addr = skb->daddr;
491         memcpy_tofs(sin, &addr, sizeof(*sin));
492   }
493   
494   skb_free_datagram(skb);
495   release_sock(sk);
496   return(copied);
497 }
498 
499 
500 int
501 udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
502          unsigned flags)
503 {
504   return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
505 }
506 
507 
508 int
509 udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
510 {
511   struct sockaddr_in sin;
512   int er;
513   
514   if (addr_len < sizeof(sin)) 
515         return(-EINVAL);
516 
517   er=verify_area(VERIFY_READ, usin, sizeof(sin));
518   if(er)
519         return er;
520 
521   memcpy_fromfs(&sin, usin, sizeof(sin));
522   if (sin.sin_family && sin.sin_family != AF_INET) 
523         return(-EAFNOSUPPORT);
524 
525   if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
526         return -EACCES;                 /* Must turn broadcast on first */
527         
528   sk->daddr = sin.sin_addr.s_addr;
529   sk->dummy_th.dest = sin.sin_port;
530   sk->state = TCP_ESTABLISHED;
531   return(0);
532 }
533 
534 
535 static void
536 udp_close(struct sock *sk, int timeout)
537 {
538   sk->inuse = 1;
539   sk->state = TCP_CLOSE;
540   if (sk->dead) destroy_sock(sk);
541     else release_sock(sk);
542 }
543 
544 
545 /* All we need to do is get the socket, and then do a checksum. */
546 int
547 udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
548         unsigned long daddr, unsigned short len,
549         unsigned long saddr, int redo, struct inet_protocol *protocol)
550 {
551   struct sock *sk;
552   struct udphdr *uh;
553 
554   uh = (struct udphdr *) skb->h.uh;
555   sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
556   if (sk == NULL) 
557   {
558         if (chk_addr(daddr) == IS_MYADDR) 
559         {
560                 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
561         }
562         /*
563          * Hmm.  We got an UDP broadcast to a port to which we
564          * don't wanna listen.  The only thing we can do now is
565          * to ignore the packet... -FvK
566          */
567         skb->sk = NULL;
568         kfree_skb(skb, FREE_WRITE);
569         return(0);
570   }
571 
572   if (uh->check && udp_check(uh, len, saddr, daddr)) {
573         DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
574         skb->sk = NULL;
575         kfree_skb(skb, FREE_WRITE);
576         return(0);
577   }
578 
579   skb->sk = sk;
580   skb->dev = dev;
581   skb->len = len;
582 
583 /* These are supposed to be switched. */
584   skb->daddr = saddr;
585   skb->saddr = daddr;
586 
587 
588   /* Charge it to the socket. */
589   if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) 
590   {
591         skb->sk = NULL;
592         kfree_skb(skb, FREE_WRITE);
593         release_sock(sk);
594         return(0);
595   }
596   sk->rmem_alloc += skb->mem_len;
597 
598   /* At this point we should print the thing out. */
599   DPRINTF((DBG_UDP, "<< \n"));
600   print_udp(uh);
601 
602   /* Now add it to the data chain and wake things up. */
603   
604   skb_queue_tail(&sk->rqueue,skb);
605 
606   skb->len = len - sizeof(*uh);
607 
608   if (!sk->dead) 
609         sk->data_ready(sk,skb->len);
610         
611   release_sock(sk);
612   return(0);
613 }
614 
615 
616 struct proto udp_prot = {
617   sock_wmalloc,
618   sock_rmalloc,
619   sock_wfree,
620   sock_rfree,
621   sock_rspace,
622   sock_wspace,
623   udp_close,
624   udp_read,
625   udp_write,
626   udp_sendto,
627   udp_recvfrom,
628   ip_build_header,
629   udp_connect,
630   NULL,
631   ip_queue_xmit,
632   ip_retransmit,
633   NULL,
634   NULL,
635   udp_rcv,
636   datagram_select,
637   udp_ioctl,
638   NULL,
639   NULL,
640   ip_setsockopt,
641   ip_getsockopt,
642   128,
643   0,
644   {NULL,},
645   "UDP"
646 };
647 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -