@@ -556,6 +556,49 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
556556 sctp_transport_put (t );
557557}
558558
559+ static void sctp_v4_err_handle (struct sctp_transport * t , struct sk_buff * skb ,
560+ __u8 type , __u8 code , __u32 info )
561+ {
562+ struct sctp_association * asoc = t -> asoc ;
563+ struct sock * sk = asoc -> base .sk ;
564+ int err = 0 ;
565+
566+ switch (type ) {
567+ case ICMP_PARAMETERPROB :
568+ err = EPROTO ;
569+ break ;
570+ case ICMP_DEST_UNREACH :
571+ if (code > NR_ICMP_UNREACH )
572+ return ;
573+ if (code == ICMP_FRAG_NEEDED ) {
574+ sctp_icmp_frag_needed (sk , asoc , t , SCTP_TRUNC4 (info ));
575+ return ;
576+ }
577+ if (code == ICMP_PROT_UNREACH ) {
578+ sctp_icmp_proto_unreachable (sk , asoc , t );
579+ return ;
580+ }
581+ err = icmp_err_convert [code ].errno ;
582+ break ;
583+ case ICMP_TIME_EXCEEDED :
584+ if (code == ICMP_EXC_FRAGTIME )
585+ return ;
586+
587+ err = EHOSTUNREACH ;
588+ break ;
589+ case ICMP_REDIRECT :
590+ sctp_icmp_redirect (sk , t , skb );
591+ default :
592+ return ;
593+ }
594+ if (!sock_owned_by_user (sk ) && inet_sk (sk )-> recverr ) {
595+ sk -> sk_err = err ;
596+ sk -> sk_error_report (sk );
597+ } else { /* Only an error on timeout */
598+ sk -> sk_err_soft = err ;
599+ }
600+ }
601+
559602/*
560603 * This routine is called by the ICMP module when it gets some
561604 * sort of error condition. If err < 0 then the socket should
@@ -574,22 +617,19 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
574617int sctp_v4_err (struct sk_buff * skb , __u32 info )
575618{
576619 const struct iphdr * iph = (const struct iphdr * )skb -> data ;
577- const int ihlen = iph -> ihl * 4 ;
578620 const int type = icmp_hdr (skb )-> type ;
579621 const int code = icmp_hdr (skb )-> code ;
580- struct sock * sk ;
581- struct sctp_association * asoc = NULL ;
622+ struct net * net = dev_net (skb -> dev );
582623 struct sctp_transport * transport ;
583- struct inet_sock * inet ;
624+ struct sctp_association * asoc ;
584625 __u16 saveip , savesctp ;
585- int err ;
586- struct net * net = dev_net (skb -> dev );
626+ struct sock * sk ;
587627
588628 /* Fix up skb to look at the embedded net header. */
589629 saveip = skb -> network_header ;
590630 savesctp = skb -> transport_header ;
591631 skb_reset_network_header (skb );
592- skb_set_transport_header (skb , ihlen );
632+ skb_set_transport_header (skb , iph -> ihl * 4 );
593633 sk = sctp_err_lookup (net , AF_INET , skb , sctp_hdr (skb ), & asoc , & transport );
594634 /* Put back, the original values. */
595635 skb -> network_header = saveip ;
@@ -598,58 +638,10 @@ int sctp_v4_err(struct sk_buff *skb, __u32 info)
598638 __ICMP_INC_STATS (net , ICMP_MIB_INERRORS );
599639 return - ENOENT ;
600640 }
601- /* Warning: The sock lock is held. Remember to call
602- * sctp_err_finish!
603- */
604641
605- switch (type ) {
606- case ICMP_PARAMETERPROB :
607- err = EPROTO ;
608- break ;
609- case ICMP_DEST_UNREACH :
610- if (code > NR_ICMP_UNREACH )
611- goto out_unlock ;
612-
613- /* PMTU discovery (RFC1191) */
614- if (ICMP_FRAG_NEEDED == code ) {
615- sctp_icmp_frag_needed (sk , asoc , transport ,
616- SCTP_TRUNC4 (info ));
617- goto out_unlock ;
618- } else {
619- if (ICMP_PROT_UNREACH == code ) {
620- sctp_icmp_proto_unreachable (sk , asoc ,
621- transport );
622- goto out_unlock ;
623- }
624- }
625- err = icmp_err_convert [code ].errno ;
626- break ;
627- case ICMP_TIME_EXCEEDED :
628- /* Ignore any time exceeded errors due to fragment reassembly
629- * timeouts.
630- */
631- if (ICMP_EXC_FRAGTIME == code )
632- goto out_unlock ;
633-
634- err = EHOSTUNREACH ;
635- break ;
636- case ICMP_REDIRECT :
637- sctp_icmp_redirect (sk , transport , skb );
638- /* Fall through to out_unlock. */
639- default :
640- goto out_unlock ;
641- }
642-
643- inet = inet_sk (sk );
644- if (!sock_owned_by_user (sk ) && inet -> recverr ) {
645- sk -> sk_err = err ;
646- sk -> sk_error_report (sk );
647- } else { /* Only an error on timeout */
648- sk -> sk_err_soft = err ;
649- }
650-
651- out_unlock :
642+ sctp_v4_err_handle (transport , skb , type , code , info );
652643 sctp_err_finish (sk , transport );
644+
653645 return 0 ;
654646}
655647
0 commit comments