source: rtems/cpukit/libnetworking/netinet/udp_usrreq.c @ ce2c216

4.104.114.84.95
Last change on this file since ce2c216 was ce2c216, checked in by Joel Sherrill <joel.sherrill@…>, on 09/14/02 at 18:18:50

2002-09-14 Vyacheslav V. Burdjanadze <wr@…>

  • kern/uipc_mbuf.c, sys/mbuf.h, netinet/udp_usrreq.c: Add optional UDP broadcast forwarding support.
  • netinet/Makefile.am: Defined FORWARD_PROTOCOL to enabled UDP broadcast forwarding.
  • Property mode set to 100644
File size: 26.3 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by the University of
16 *      California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *      @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
34 *      $Id$
35 */
36
37
38#include <sys/param.h>
39#include <sys/queue.h>
40#include <sys/systm.h>
41#include <sys/malloc.h>
42#include <sys/mbuf.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/errno.h>
47#include <sys/stat.h>
48#include <sys/kernel.h>
49#include <sys/sysctl.h>
50#include <sys/syslog.h>
51
52#include <net/if.h>
53#include <net/pf.h>
54#include <net/route.h>
55
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/ip.h>
59#include <netinet/in_pcb.h>
60#include <netinet/in_var.h>
61#include <netinet/ip_var.h>
62#include <netinet/ip_icmp.h>
63#include <netinet/udp.h>
64#include <netinet/udp_var.h>
65#include <time.h>
66
67#undef malloc
68#undef free
69
70/*
71 * UDP protocol implementation.
72 * Per RFC 768, August, 1980.
73 */
74#ifndef COMPAT_42
75static int      udpcksum = 1;
76#else
77static int      udpcksum = 0;           /* XXX */
78#endif
79SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
80                &udpcksum, 0, "Calculate UDP checksum");
81               
82
83#ifdef FORWARD_PROTOCOL
84
85static int
86udp_store(struct mbuf *m);
87
88static int
89udp_doutput(struct in_addr dst);
90
91
92/*
93 * To implement udp broadcast forwarding we should check ``broadcast storm''
94 * condition that can be caused if there is alternate ways between two subnets
95 * and efficiently cut such loops. This can be done by caching sensetive packet
96 * information and performing tests on it:
97 * 1. If we got packet that is not in our cache we pass this packet and
98 *    add it into cache. If there is no room in cache - LRU packet is discarded
99 * 2. If we got packet that already in our cache we make it MRU and:         
100 *    We check ttl of ip packet - if it same or greater as in cache we just
101 *    pass it. If it less - just drop this packet.
102 */
103
104#define MAXUDPCACHE  10  /* Seems to be reasonable size */
105#define UDPMAXEXPIRE 30  /* 30 sec expire cache         */
106
107struct packet_cache {
108    unsigned8      pc_ttl;   /* IP packet TTL */
109    unsigned16     pc_sum;   /* UDP packet checksum */
110    struct in_addr pc_src;   /* IP packet source address*/
111    struct udphdr  pc_uh;    /* UDP packet header */
112    time_t  pc_time;         /* Expiry value */
113    struct packet_cache *next , *prev;
114   
115};
116
117static struct packet_cache *udp_cache = NULL;
118
119#endif
120
121       
122static u_long   udp_sendspace = 9216;           /* really max datagram size */
123                                        /* 40 1K datagrams */
124SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
125        &udp_sendspace, 0, "Maximum UDP datagram size");
126
127static u_long   udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
128SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
129        &udp_recvspace, 0, "Maximum UDP receive buffer size");
130       
131
132static struct   inpcbhead udb;          /* from udp_var.h */
133static struct   inpcbinfo udbinfo;
134
135#ifndef UDBHASHSIZE
136#define UDBHASHSIZE 64
137#endif
138
139/*
140 * UDP statistics
141 */
142struct udpstat udpstat;
143
144SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RW,
145        &udpstat, udpstat, "UDP statistic");
146
147static struct   sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
148
149static  void udp_detach __P((struct inpcb *));
150static  int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *,
151                            struct mbuf *));
152static  void udp_notify __P((struct inpcb *, int));
153
154
155/* Added by Vasilkov. This system call is used by snmp agent code.
156 *
157 */
158void udp_get_struct_udb (struct inpcbhead * strudb)
159{
160        memcpy ((char*)strudb, (char*)&udb, sizeof(struct inpcbhead));
161}
162
163
164/*
165 * Register sysctl's
166 */
167void
168sysctl_register_udp_usrreq() {
169
170        sysctl_register(_net_inet_udp,checksum);
171        sysctl_register(_net_inet_udp,maxdgram);
172        sysctl_register(_net_inet_udp,stats);
173        sysctl_register(_net_inet_udp,recvspace);
174}
175
176void
177udp_init()
178{
179        LIST_INIT(&udb);
180        udbinfo.listhead = &udb;
181        udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
182       
183}
184
185#ifdef FORWARD_PROTOCOL
186static unsigned char udp_ports[65536/8];
187
188/*
189 * Enable/Disable udp port forwarding
190 */
191int udp_forward_port(int port,int forward) {
192
193    int byte = port/8;
194    int offset = port%8;
195   
196    if (forward)
197        udp_ports[byte] |= (0x80 >> offset);
198    else
199        udp_ports[byte] &= ~(0x80 >> offset);
200       
201    return 0;
202}
203
204/*
205 * Check if port should be forwarded
206 */
207static int udp_if_forward(int port) {
208
209    int byte = port/8;
210    int offset = port%8;
211   
212    return (udp_ports[byte] & (0x80 >> offset));
213
214}
215
216/*
217 * Get packet_cache from mbuf
218 */
219static int udp_pc_from_m(struct packet_cache *pc, struct mbuf *m) {
220
221    struct ip *iph = mtod(m,struct ip *);
222    struct udphdr *uh = (struct udphdr *)((char *)iph + sizeof(struct ip));
223   
224    pc->pc_ttl  = iph->ip_ttl;
225    pc->pc_sum  = uh->uh_sum;
226    pc->pc_src  = iph->ip_src;
227    pc->pc_uh   = *uh;
228    pc->pc_time = time(NULL) + UDPMAXEXPIRE;
229   
230    return 0;
231}
232
233/*
234 * Make cache entry MRU
235 */
236static void udp_make_mru(struct packet_cache *pc) {
237
238    if (pc == udp_cache)
239        return ;
240   
241    /* MRU it */
242    if (pc->prev) pc->prev->next = pc->next;
243    if (pc->next) pc->next->prev = pc->prev;
244   
245    pc->prev = NULL;
246    pc->next = udp_cache;
247    udp_cache->prev = pc;
248    udp_cache = pc;
249   
250    pc->pc_time = time(NULL) + UDPMAXEXPIRE;
251   
252    /*
253     * HUGE FIXME: pc_sum should be strong checksum of udp data. md5 seems
254     * to be ok.
255     */
256   
257}
258
259
260/*
261 *
262 */
263#define UDP_PASS 0
264#define UDP_DROP 1
265
266static int udp_analyze(struct mbuf *m) {
267
268    time_t now;
269    struct packet_cache *pc,my,*empty = NULL;
270   
271   
272    /*
273     * If still no cache allocated - allocate it
274     */
275    if (!udp_cache) {
276        int i;
277       
278        for (i=0;i<MAXUDPCACHE;i++) {
279            struct packet_cache *pc = malloc(sizeof(struct packet_cache));
280            if (pc) {
281                memset(pc,0,sizeof(struct packet_cache));
282                pc->next = udp_cache;
283                if (udp_cache) udp_cache->prev = pc;
284                udp_cache = pc;
285            }
286        }
287    }
288   
289    /*
290     * If no memory - just drop packet
291     */
292    if (!udp_cache)
293        return UDP_DROP;
294   
295    pc = udp_cache;
296    now = time(NULL);
297   
298    udp_pc_from_m(&my,m);
299   
300    if (my.pc_ttl <= IPTTLDEC)
301        return UDP_DROP;
302   
303    while( pc ) {
304   
305        if (pc->pc_ttl) { /*Non-empty entry*/
306            if (pc->pc_time < now) {
307                pc->pc_ttl = 0;
308                empty = pc;
309#ifdef FORWARD_DEBUG           
310/*              printf("Entry expired :%s, sum %lu\n",inet_ntoa(pc->pc_src),pc->pc_sum);*/
311#endif         
312            }
313            else {
314                if ((pc->pc_sum == my.pc_sum) &&
315                    (pc->pc_src.s_addr == my.pc_src.s_addr) &&
316                    (pc->pc_uh.uh_dport == my.pc_uh.uh_dport) &&
317                    (pc->pc_uh.uh_ulen == my.pc_uh.uh_ulen)) {
318                   
319#ifdef FORWARD_DEBUG               
320/*                      printf("Cache HIT\n");*/
321#endif                 
322                   
323                        udp_make_mru(pc);
324                        if (pc->pc_ttl <= my.pc_ttl)
325                            return UDP_PASS;
326                       
327#ifdef FORWARD_DEBUG                   
328/*                      printf("Loop detected!\n");*/
329#endif                 
330                        return UDP_DROP;
331                    }
332                   
333            }
334        }
335        else
336            empty = pc;
337   
338        pc = pc->next;
339    }
340   
341    /*
342     * If no free entry in cache - remove LRU entry
343     */
344    if (!empty) {
345   
346#ifdef FORWARD_DEBUG   
347/*      printf("Cache full, removing LRU\n");*/
348#endif 
349        empty = udp_cache;
350        while(empty->next)
351            empty = empty->next;
352       
353    }
354   
355    /* Cache it and make MRU */
356#ifdef FORWARD_DEBUG   
357/*    printf("Caching packet\n");*/
358#endif   
359    udp_make_mru(empty);
360   
361    empty->pc_ttl  = my.pc_ttl;
362    empty->pc_sum  = my.pc_sum;
363    empty->pc_src  = my.pc_src;
364    empty->pc_uh   = my.pc_uh;
365    empty->pc_time = my.pc_time;
366
367    return UDP_PASS;
368}
369
370
371
372#endif /* FORWARD_PROTOCOL */
373
374void
375udp_input(m, iphlen)
376        register struct mbuf *m;
377        int iphlen;
378{
379        register struct ip *ip;
380        register struct udphdr *uh;
381        register struct inpcb *inp;
382        struct mbuf *opts = 0;
383        int len;
384        struct ip save_ip;
385        struct ifnet *ifp = m->m_pkthdr.rcvif;
386        int log_in_vain = 0;
387        int blackhole = 0;
388
389
390        /*
391         * Fetch logging flag from interface
392         */     
393        if (ifp->if_ip.ifi_udp & IFNET_UDP_LOG_IN_VAIN)
394            log_in_vain = 1;
395           
396        /*
397         * Check if we should silently discard refused connects
398         */
399        if (ifp->if_ip.ifi_udp & IFNET_UDP_BLACKHOLE)
400            blackhole = 1;
401
402        udpstat.udps_ipackets++;
403
404        /*
405         * Strip IP options, if any; should skip this,
406         * make available to user, and use on returned packets,
407         * but we don't yet have a way to check the checksum
408         * with options still present.
409         */
410        if (iphlen > sizeof (struct ip)) {
411                ip_stripoptions(m, (struct mbuf *)0);
412                iphlen = sizeof(struct ip);
413        }
414
415        /*
416         * Get IP and UDP header together in first mbuf.
417         */
418        ip = mtod(m, struct ip *);
419        if (m->m_len < iphlen + sizeof(struct udphdr)) {
420                if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
421                        udpstat.udps_hdrops++;
422                        return;
423                }
424                ip = mtod(m, struct ip *);
425        }
426        uh = (struct udphdr *)((caddr_t)ip + iphlen);
427
428#ifdef FORWARD_PROTOCOL   
429        if (udp_if_forward(ntohs(uh->uh_dport))) {
430            if (in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
431                udp_store(m);
432        }
433#endif 
434
435
436        /*
437         * Make mbuf data length reflect UDP length.
438         * If not enough data to reflect UDP length, drop.
439         */
440        len = ntohs((u_short)uh->uh_ulen);
441        if (ip->ip_len != len) {
442                if (len > ip->ip_len || len < sizeof(struct udphdr)) {
443                        udpstat.udps_badlen++;
444                        goto bad;
445                }
446                m_adj(m, len - ip->ip_len);
447                /* ip->ip_len = len; */
448        }
449        /*
450         * Save a copy of the IP header in case we want restore it
451         * for sending an ICMP error message in response.
452         */
453        save_ip = *ip;
454
455        /*
456         * Checksum extended UDP header and data.
457         */
458
459        if (uh->uh_sum) {
460               
461                ((struct ipovly *)ip)->ih_next = 0;
462                ((struct ipovly *)ip)->ih_prev = 0;
463                ((struct ipovly *)ip)->ih_x1 = 0;
464                ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
465                uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
466                if (uh->uh_sum) {
467                        udpstat.udps_badsum++;
468                        m_freem(m);
469                        return;
470                }
471        }
472
473        if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
474            in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
475                struct inpcb *last;
476               
477#ifdef FORWARD_PROTOCOL         
478                /*
479                 * If our router configured to route broadcasts (this may
480                 * be required to enable NetBIOS thru router)
481                 */
482
483                if (udp_if_forward(ntohs(uh->uh_dport))) {
484                    /*
485                     * For each interface that allow directed broadcast
486                     * we should reflect this packet with destanation address
487                     * equal to interface subnet broadcast address
488                     */
489                    struct ifnet *ifp = ifnet;
490                   
491                    /*
492                     * Checksum udp data + header without address information
493                     */
494                    m->m_len  -= sizeof(struct ip);
495                    m->m_data += sizeof(struct ip);
496                    uh->uh_sum = in_cksum(m, len/* + sizeof (struct ip)*/);
497                    m->m_len  += sizeof(struct ip);
498                    m->m_data -= sizeof(struct ip);
499                   
500                    *ip = save_ip;
501                   
502                    if (udp_analyze(m) == UDP_DROP) {
503#ifdef FORWARD_DEBUG
504                        printf("UDP DROP <%s:%d>, ttl=%d, sum=%lu\n",inet_ntoa(ip->ip_src),uh->uh_sport,ip->ip_ttl,uh->uh_sum);
505#endif                                 
506                        goto bad;
507
508                    }
509                   
510#ifdef FORWARD_DEBUG               
511                    printf("UDP PASS <%s:%d>, ttl=%d, sum=%lu\n",inet_ntoa(ip->ip_src),uh->uh_sport,ip->ip_ttl,uh->uh_sum);
512#endif             
513
514                   
515                    while (ifp) {
516                   
517                        if ((ifp != m->m_pkthdr.rcvif) &&
518                            !(ifp->if_flags & IFF_LOOPBACK) /*&&
519                            (ifp->if_ip.ifi_udp & IFNET_UDP_FORWARD_PROTOCOL)*/) {
520                           
521                            struct ifaddr *ifa = ifp->if_addrlist;
522                           
523#ifdef FORWARD_DEBUG                       
524                            /*printf("\tForwarding through %s%d\n",ifp->if_name,ifp->if_unit);*/
525#endif                     
526                           
527                            while(ifa) {
528
529                               
530                                if  (ifa->ifa_addr->sa_family == AF_INET) {
531                   
532
533                               
534                                    if (ifp->if_flags | IFF_BROADCAST) {
535                                            if (ifa->ifa_dstaddr)
536                                            ip->ip_dst.s_addr = ((struct sockaddr_in *)(ifa->ifa_dstaddr))->sin_addr.s_addr;
537                                        else {
538                                            ip->ip_dst.s_addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr;
539                                            ip->ip_dst.s_addr &= ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr;
540                                            ip->ip_dst.s_addr |= ~(((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr);
541                                        }
542                                    }
543                                    else
544                                        goto bad;
545                                       
546                                    /*Calculate correct UDP checksum*/
547                                   
548                                   
549#ifdef FORWARD_DEBUG
550                                    printf("\t\tForwarding to %s\n",inet_ntoa(ip->ip_dst));
551#endif
552                                    udp_doutput(ip->ip_dst);
553
554                                }
555
556                                ifa = ifa->ifa_next;
557                            }
558                        }
559                        ifp = ifp->if_next;
560                    }
561                   
562                    if (opts)
563                        m_freem(opts);
564                    if (m)
565                        m_freem(m);
566                       
567                    /*
568                     * FIXME: should I also pass udp packet to socket?
569                     */
570
571                    return ;
572                }
573#endif /* FORWARD_PROTOCOL */           
574               
575                /*
576                 * Deliver a multicast or broadcast datagram to *all* sockets
577                 * for which the local and remote addresses and ports match
578                 * those of the incoming datagram.  This allows more than
579                 * one process to receive multi/broadcasts on the same port.
580                 * (This really ought to be done for unicast datagrams as
581                 * well, but that would cause problems with existing
582                 * applications that open both address-specific sockets and
583                 * a wildcard socket listening to the same port -- they would
584                 * end up receiving duplicates of every unicast datagram.
585                 * Those applications open the multiple sockets to overcome an
586                 * inadequacy of the UDP socket interface, but for backwards
587                 * compatibility we avoid the problem here rather than
588                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
589                 */
590
591                /*
592                 * Construct sockaddr format source address.
593                 */
594                udp_in.sin_port = uh->uh_sport;
595                udp_in.sin_addr = ip->ip_src;
596                m->m_len -= sizeof (struct udpiphdr);
597                m->m_data += sizeof (struct udpiphdr);
598                /*
599                 * Locate pcb(s) for datagram.
600                 * (Algorithm copied from raw_intr().)
601                 */
602                last = NULL;
603                for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
604                        if (inp->inp_lport != uh->uh_dport)
605                                continue;
606                        if (inp->inp_laddr.s_addr != INADDR_ANY) {
607                                if (inp->inp_laddr.s_addr !=
608                                    ip->ip_dst.s_addr)
609                                        continue;
610                        }
611                        if (inp->inp_faddr.s_addr != INADDR_ANY) {
612                                if (inp->inp_faddr.s_addr !=
613                                    ip->ip_src.s_addr ||
614                                    inp->inp_fport != uh->uh_sport)
615                                        continue;
616                        }
617
618                        if (last != NULL) {
619                                struct mbuf *n;
620
621                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
622                                        if (last->inp_flags & INP_CONTROLOPTS
623                                            || last->inp_socket->so_options & SO_TIMESTAMP)
624                                                ip_savecontrol(last, &opts, ip, n);
625                                        if (sbappendaddr(&last->inp_socket->so_rcv,
626                                                (struct sockaddr *)&udp_in,
627                                                n, opts) == 0) {
628                                                m_freem(n);
629                                                if (opts)
630                                                    m_freem(opts);
631                                                udpstat.udps_fullsock++;
632                                        } else
633                                                sorwakeup(last->inp_socket);
634                                        opts = 0;
635                                }
636                        }
637                        last = inp;
638                        /*
639                         * Don't look for additional matches if this one does
640                         * not have either the SO_REUSEPORT or SO_REUSEADDR
641                         * socket options set.  This heuristic avoids searching
642                         * through all pcbs in the common case of a non-shared
643                         * port.  It * assumes that an application will never
644                         * clear these options after setting them.
645                         */
646                        if (((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0))
647                                break;
648                }
649
650                if (last == NULL) {
651                        /*
652                         * No matching pcb found; discard datagram.
653                         * (No need to send an ICMP Port Unreachable
654                         * for a broadcast or multicast datgram.)
655                         */
656                        udpstat.udps_noport++;
657                        udpstat.udps_noportbcast++;
658                        goto bad;
659                }
660                if (last->inp_flags & INP_CONTROLOPTS
661                    || last->inp_socket->so_options & SO_TIMESTAMP)
662                        ip_savecontrol(last, &opts, ip, m);
663                if (sbappendaddr(&last->inp_socket->so_rcv,
664                     (struct sockaddr *)&udp_in,
665                     m, opts) == 0) {
666                        udpstat.udps_fullsock++;
667                        goto bad;
668                }
669                sorwakeup(last->inp_socket);
670                return;
671        }
672        /*
673         * Locate pcb for datagram.
674         */
675        inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport,
676            ip->ip_dst, uh->uh_dport, 1);
677        if (inp == NULL) {
678                if (log_in_vain) {
679                        char bufdst[20];
680                        char bufsrc[20];
681                       
682                        inet_ntop(AF_INET,&(ip->ip_dst),bufdst,sizeof(bufdst));
683                        inet_ntop(AF_INET,&(ip->ip_src),bufdst,sizeof(bufsrc));
684
685                        log(LOG_INFO, "Connection attempt to UDP %s:%d"
686                            " from %s:%d\n",
687                                bufdst, ntohs(uh->uh_dport),
688                                bufsrc, ntohs(uh->uh_sport));
689                }
690                udpstat.udps_noport++;
691                if (m->m_flags & (M_BCAST | M_MCAST)) {
692                        udpstat.udps_noportbcast++;
693                        goto bad;
694                }
695                *ip = save_ip;
696               
697                /*
698                 * If we forced to be silent as much as possible..
699                 */
700                if (blackhole)
701                    goto bad;
702                   
703                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
704                return;
705        }
706
707        /*
708         * Construct sockaddr format source address.
709         * Stuff source address and datagram in user buffer.
710         */
711        udp_in.sin_port = uh->uh_sport;
712        udp_in.sin_addr = ip->ip_src;
713        if (inp->inp_flags & INP_CONTROLOPTS
714            || inp->inp_socket->so_options & SO_TIMESTAMP)
715                ip_savecontrol(inp, &opts, ip, m);
716        iphlen += sizeof(struct udphdr);
717        m->m_len -= iphlen;
718        m->m_pkthdr.len -= iphlen;
719        m->m_data += iphlen;
720        if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
721            m, opts) == 0) {
722                udpstat.udps_fullsock++;
723                goto bad;
724        }
725        sorwakeup(inp->inp_socket);
726        return;
727bad:
728        m_freem(m);
729        if (opts)
730            m_freem(opts);
731}
732
733/*
734 * Notify a udp user of an asynchronous error;
735 * just wake up so that he can collect error status.
736 */
737static void
738udp_notify(inp, errnum)
739        register struct inpcb *inp;
740        int errnum;
741{
742        inp->inp_socket->so_error = errnum;
743        sorwakeup(inp->inp_socket);
744        sowwakeup(inp->inp_socket);
745}
746
747void
748udp_ctlinput(cmd, sa, vip)
749        int cmd;
750        struct sockaddr *sa;
751        void *vip;
752{
753        register struct ip *ip = vip;
754        register struct udphdr *uh;
755
756        if (!PRC_IS_REDIRECT(cmd) &&
757            ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
758                return;
759        if (ip) {
760                uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
761                in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
762                        cmd, udp_notify);
763        } else
764                in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
765}
766
767static int
768udp_output(inp, m, addr, control)
769        register struct inpcb *inp;
770        register struct mbuf *m;
771        struct mbuf *addr, *control;
772{
773        register struct udpiphdr *ui;
774        register int len = m->m_pkthdr.len;
775        struct in_addr laddr;
776        int s = 0, error = 0;
777
778        if (control)
779                m_freem(control);               /* XXX */
780
781        if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
782                error = EMSGSIZE;
783                goto release;
784        }
785
786        if (addr) {
787                laddr = inp->inp_laddr;
788                if (inp->inp_faddr.s_addr != INADDR_ANY) {
789                        error = EISCONN;
790                        goto release;
791                }
792                /*
793                 * Must block input while temporarily connected.
794                 */
795                s = splnet();
796                error = in_pcbconnect(inp, addr);
797                if (error) {
798                        splx(s);
799                        goto release;
800                }
801        } else {
802                if (inp->inp_faddr.s_addr == INADDR_ANY) {
803                        error = ENOTCONN;
804                        goto release;
805                }
806        }
807        /*
808         * Calculate data length and get a mbuf
809         * for UDP and IP headers.
810         */
811        M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
812        if (m == 0) {
813                error = ENOBUFS;
814                if (addr)
815                        splx(s);
816                goto release;
817        }
818
819        /*
820         * Fill in mbuf with extended UDP header
821         * and addresses and length put into network format.
822         */
823        ui = mtod(m, struct udpiphdr *);
824        ui->ui_next = ui->ui_prev = 0;
825        ui->ui_x1 = 0;
826        ui->ui_pr = IPPROTO_UDP;
827        ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
828        ui->ui_src = inp->inp_laddr;
829        ui->ui_dst = inp->inp_faddr;
830        ui->ui_sport = inp->inp_lport;
831        ui->ui_dport = inp->inp_fport;
832        ui->ui_ulen = ui->ui_len;
833
834        /*
835         * Stuff checksum and output datagram.
836         */
837        ui->ui_sum = 0;
838        if (udpcksum) { /*FIXME: should be taken from ouput interface */
839            if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
840                ui->ui_sum = 0xffff;
841        }
842        ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
843        ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl;    /* XXX */
844        ((struct ip *)ui)->ip_tos = inp->inp_ip_tos;    /* XXX */
845        udpstat.udps_opackets++;
846        error = ip_output(m, inp->inp_options, &inp->inp_route,
847            inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
848            inp->inp_moptions,0);
849
850        if (addr) {
851                in_pcbdisconnect(inp);
852                inp->inp_laddr = laddr;
853                splx(s);
854        }
855        return (error);
856
857release:
858        m_freem(m);
859        return (error);
860}
861
862
863/*ARGSUSED*/
864int
865udp_usrreq(so, req, m, addr, control)
866        struct socket *so;
867        int req;
868        struct mbuf *m, *addr, *control;
869{
870        struct inpcb *inp = sotoinpcb(so);
871        int error = 0;
872        int s;
873
874        if (req == PRU_CONTROL)
875                return (in_control(so, (u_long)m, (caddr_t)addr,
876                        (struct ifnet *)control));
877        if (inp == NULL && req != PRU_ATTACH) {
878                error = EINVAL;
879                goto release;
880        }
881        /*
882         * Note: need to block udp_input while changing
883         * the udp pcb queue and/or pcb addresses.
884         */
885        switch (req) {
886
887        case PRU_ATTACH:
888                if (inp != NULL) {
889                        error = EINVAL;
890                        break;
891                }
892                s = splnet();
893                error = in_pcballoc(so, &udbinfo);
894                splx(s);
895                if (error)
896                        break;
897                error = soreserve(so, udp_sendspace, udp_recvspace);
898                if (error)
899                        break;
900                ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; /*FIXME: fetch ttl from interface first*/
901                break;
902
903        case PRU_DETACH:
904                udp_detach(inp);
905                break;
906
907        case PRU_BIND:
908                s = splnet();
909                error = in_pcbbind(inp, addr);
910                splx(s);
911                break;
912
913        case PRU_LISTEN:
914                error = EOPNOTSUPP;
915                break;
916
917        case PRU_CONNECT:
918                if (inp->inp_faddr.s_addr != INADDR_ANY) {
919                        error = EISCONN;
920                        break;
921                }
922                s = splnet();
923                error = in_pcbconnect(inp, addr);
924                splx(s);
925                if (error == 0)
926                        soisconnected(so);
927                break;
928
929        case PRU_CONNECT2:
930                error = EOPNOTSUPP;
931                break;
932
933        case PRU_ACCEPT:
934                error = EOPNOTSUPP;
935                break;
936
937        case PRU_DISCONNECT:
938                if (inp->inp_faddr.s_addr == INADDR_ANY) {
939                        error = ENOTCONN;
940                        break;
941                }
942                s = splnet();
943                in_pcbdisconnect(inp);
944                inp->inp_laddr.s_addr = INADDR_ANY;
945                splx(s);
946                so->so_state &= ~SS_ISCONNECTED;                /* XXX */
947                break;
948
949        case PRU_SHUTDOWN:
950                socantsendmore(so);
951                break;
952
953        case PRU_SEND:
954                return (udp_output(inp, m, addr, control));
955
956        case PRU_ABORT:
957                soisdisconnected(so);
958                udp_detach(inp);
959                break;
960
961        case PRU_SOCKADDR:
962                in_setsockaddr(inp, addr);
963                break;
964
965        case PRU_PEERADDR:
966                in_setpeeraddr(inp, addr);
967                break;
968
969        case PRU_SENSE:
970                /*
971                 * stat: don't bother with a blocksize.
972                 */
973                return (0);
974
975        case PRU_SENDOOB:
976        case PRU_FASTTIMO:
977        case PRU_SLOWTIMO:
978        case PRU_PROTORCV:
979        case PRU_PROTOSEND:
980                error =  EOPNOTSUPP;
981                break;
982
983        case PRU_RCVD:
984        case PRU_RCVOOB:
985                return (EOPNOTSUPP);    /* do not free mbuf's */
986
987        default:
988                panic("udp_usrreq");
989        }
990
991release:
992        if (control) {
993                printf("udp control data unexpectedly retained\n");
994                m_freem(control);
995        }
996        if (m)
997                m_freem(m);
998        return (error);
999}
1000
1001static void
1002udp_detach(inp)
1003        struct inpcb *inp;
1004{
1005        int s = splnet();
1006
1007        in_pcbdetach(inp);
1008        splx(s);
1009}
1010
1011#ifdef FORWARD_PROTOCOL
1012
1013static int ttl;
1014static struct in_addr src;
1015static int sport,dport;
1016static char buf[8096];
1017static int len;
1018
1019/*
1020 * Store packet
1021 */
1022static int
1023udp_store(struct mbuf *m) {
1024
1025    struct ip *iph = mtod(m,struct ip *);
1026    struct udphdr *uh = iph + 1;
1027
1028#ifdef FORWARD_DEBUG
1029    printf("Storing %d bytes at offset %d of total packet len %d\n",uh->uh_ulen - sizeof(struct udphdr),sizeof(struct ip) + sizeof(struct udphdr),m->m_pkthdr.len);
1030#endif   
1031   
1032    if (m_copydata(m,sizeof(struct ip) + sizeof(struct udphdr),
1033                 uh->uh_ulen - sizeof(struct udphdr),
1034                 buf)<0) {
1035        ttl = 0;
1036        return -1;
1037    }
1038                 
1039
1040    ttl = iph->ip_ttl;
1041    src = iph->ip_src;
1042    sport = uh->uh_sport;
1043    dport = uh->uh_dport;
1044    len = uh->uh_ulen - sizeof(struct udphdr);
1045
1046    return 0;
1047}
1048
1049/*
1050 * Pull packet to network
1051 */
1052static int
1053udp_doutput(struct in_addr dst) {
1054
1055
1056    struct udpiphdr *ui;
1057    struct mbuf *m;
1058    int error;
1059    struct route ro;
1060   
1061    if (ttl <= 1)
1062        return -1;
1063   
1064    m = m_gethdr(M_DONTWAIT,MT_DATA);
1065       
1066    if (!m) {
1067#ifdef FORWARD_DEBUG   
1068        printf("udp_doutput() : No buffers available\n");
1069#endif 
1070        return -1;
1071    }
1072
1073    m->m_pkthdr.len = 0;
1074    m->m_pkthdr.rcvif = NULL;   
1075    m->m_len = MHLEN;
1076   
1077    if (m_copyback(m,0,len,buf)<0) {
1078        m_freem(m);
1079        return -1;
1080    }
1081   
1082    M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
1083   
1084    if (!m) {
1085#ifdef FORWARD_DEBUG   
1086        printf("udp_douptut() : No buffers available\n");
1087#endif 
1088        return -1;
1089    }
1090
1091    /*
1092     * Fill in mbuf with extended UDP header
1093     * and addresses and length put into network format.
1094     */
1095    ui = mtod(m, struct udpiphdr *);
1096    ui->ui_next = ui->ui_prev = 0;
1097    ui->ui_x1 = 0;
1098    ui->ui_pr = IPPROTO_UDP;
1099    ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
1100    ui->ui_src = src;
1101    ui->ui_dst = dst;
1102    ui->ui_sport = sport;
1103    ui->ui_dport = dport;
1104    ui->ui_ulen = ui->ui_len;
1105
1106    /*
1107     * Stuff checksum and output datagram.
1108     */
1109    ui->ui_sum = 0;
1110    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
1111        ui->ui_sum = 0xffff;
1112       
1113       
1114    ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1115    ((struct ip *)ui)->ip_ttl = ttl - 1;
1116    ((struct ip *)ui)->ip_tos = 0;
1117   
1118    bzero(&ro, sizeof ro);
1119   
1120    udpstat.udps_opackets++;
1121
1122#ifdef FORWARD_DEBUG   
1123    {
1124        struct mbuf *n = m;
1125        printf("Sending buffer chain: ");
1126        while (n) {
1127            printf("[%d] ",n->m_len);
1128            n = n->m_next;
1129        }
1130        printf("\n");
1131       
1132    }
1133#endif   
1134   
1135    error = ip_output(m, NULL, &ro,IP_ALLOWBROADCAST,NULL,0);
1136
1137    if (ro.ro_rt)
1138        RTFREE(ro.ro_rt);
1139       
1140    return error;
1141}
1142
1143#endif /* FORWARD_PROTOCOL */
Note: See TracBrowser for help on using the repository browser.