4faf6ca087738a465fd29a6f196dbce3c05cee31
[dragonfly.git] / sys / netinet / raw_ip.c
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1993
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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)raw_ip.c    8.7 (Berkeley) 5/15/95
30  * $FreeBSD: src/sys/netinet/raw_ip.c,v 1.64.2.16 2003/08/24 08:24:38 hsu Exp $
31  */
32
33 #include "opt_inet6.h"
34 #include "opt_carp.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/jail.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/proc.h>
43 #include <sys/priv.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/sysctl.h>
48
49 #include <sys/socketvar2.h>
50 #include <sys/msgport2.h>
51
52 #include <machine/stdarg.h>
53
54 #include <net/if.h>
55 #ifdef CARP
56 #include <net/if_types.h>
57 #endif
58 #include <net/route.h>
59
60 #define _IP_VHL
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/in_pcb.h>
65 #include <netinet/in_var.h>
66 #include <netinet/ip_var.h>
67
68 #include <net/ip_mroute/ip_mroute.h>
69 #include <net/ipfw/ip_fw.h>
70 #include <net/ipfw3/ip_fw.h>
71 #include <net/dummynet/ip_dummynet.h>
72 #include <net/dummynet3/ip_dummynet3.h>
73
74 struct  inpcbinfo ripcbinfo;
75 struct  inpcbportinfo ripcbportinfo;
76
77 /*
78  * hooks for multicast routing. They all default to NULL,
79  * so leave them not initialized and rely on BSS being set to 0.
80  */
81
82 /* The socket used to communicate with the multicast routing daemon.  */
83 struct socket  *ip_mrouter;
84
85 /* The various mrouter and rsvp functions */
86 int (*ip_mrouter_set)(struct socket *, struct sockopt *);
87 int (*ip_mrouter_get)(struct socket *, struct sockopt *);
88 int (*ip_mrouter_done)(void);
89 int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
90                 struct ip_moptions *);
91 int (*mrt_ioctl)(u_long, caddr_t);
92 int (*legal_vif_num)(int);
93 u_long (*ip_mcast_src)(int);
94
95 int (*rsvp_input_p)(struct mbuf **, int *, int);
96 int (*ip_rsvp_vif)(struct socket *, struct sockopt *);
97 void (*ip_rsvp_force_done)(struct socket *);
98
99 /*
100  * Nominal space allocated to a raw ip socket.
101  */
102 #define RIPSNDQ         8192
103 #define RIPRCVQ         8192
104
105 /*
106  * Raw interface to IP protocol.
107  */
108
109 /*
110  * Initialize raw connection block queue.
111  */
112 void
113 rip_init(void)
114 {
115         in_pcbinfo_init(&ripcbinfo, 0, FALSE);
116         in_pcbportinfo_init(&ripcbportinfo, 1, 0);
117         /*
118          * XXX We don't use the hash list for raw IP, but it's easier
119          * to allocate a one entry hash list than it is to check all
120          * over the place for hashbase == NULL.
121          */
122         ripcbinfo.hashbase = hashinit(1, M_PCB, &ripcbinfo.hashmask);
123         in_pcbportinfo_set(&ripcbinfo, &ripcbportinfo, 1);
124         ripcbinfo.wildcardhashbase = hashinit(1, M_PCB,
125                                               &ripcbinfo.wildcardhashmask);
126         ripcbinfo.ipi_size = sizeof(struct inpcb);
127 }
128
129 /*
130  * Setup generic address and protocol structures
131  * for raw_input routine, then pass them along with
132  * mbuf chain.
133  */
134 int
135 rip_input(struct mbuf **mp, int *offp, int proto)
136 {
137         struct sockaddr_in ripsrc = { sizeof ripsrc, AF_INET };
138         struct mbuf *m = *mp;
139         struct ip *ip = mtod(m, struct ip *);
140         struct inpcb *inp;
141         struct inpcb *last = NULL;
142         struct mbuf *opts = NULL;
143
144         ASSERT_NETISR0;
145
146         *mp = NULL;
147
148         ripsrc.sin_addr = ip->ip_src;
149         LIST_FOREACH(inp, &ripcbinfo.pcblisthead, inp_list) {
150                 if (inp->inp_flags & INP_PLACEMARKER)
151                         continue;
152 #ifdef INET6
153                 if (!INP_ISIPV4(inp))
154                         continue;
155 #endif
156                 if (inp->inp_ip_p && inp->inp_ip_p != proto)
157                         continue;
158                 if (inp->inp_laddr.s_addr != INADDR_ANY &&
159                     inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
160                         continue;
161                 if (inp->inp_faddr.s_addr != INADDR_ANY &&
162                     inp->inp_faddr.s_addr != ip->ip_src.s_addr)
163                         continue;
164                 if (last) {
165                         struct mbuf *n = m_copypacket(m, M_NOWAIT);
166
167                         if (n) {
168                                 lwkt_gettoken(&last->inp_socket->so_rcv.ssb_token);
169                                 if (last->inp_flags & INP_CONTROLOPTS ||
170                                     last->inp_socket->so_options & SO_TIMESTAMP)
171                                     ip_savecontrol(last, &opts, ip, n);
172                                 if (ssb_appendaddr(&last->inp_socket->so_rcv,
173                                             (struct sockaddr *)&ripsrc, n,
174                                             opts) == 0) {
175                                         /* should notify about lost packet */
176                                         m_freem(n);
177                                         if (opts)
178                                             m_freem(opts);
179                                 } else {
180                                         sorwakeup(last->inp_socket);
181                                 }
182                                 lwkt_reltoken(&last->inp_socket->so_rcv.ssb_token);
183                                 opts = NULL;
184                         }
185                 }
186                 last = inp;
187         }
188         /* Check the minimum TTL for socket. */
189         if (last && ip->ip_ttl < last->inp_ip_minttl) {
190                 m_freem(opts);
191                 ipstat.ips_delivered--;
192         } else if (last) {
193                 if (last->inp_flags & INP_CONTROLOPTS ||
194                     last->inp_socket->so_options & SO_TIMESTAMP)
195                         ip_savecontrol(last, &opts, ip, m);
196                 lwkt_gettoken(&last->inp_socket->so_rcv.ssb_token);
197                 if (ssb_appendaddr(&last->inp_socket->so_rcv,
198                     (struct sockaddr *)&ripsrc, m, opts) == 0) {
199                         m_freem(m);
200                         if (opts)
201                             m_freem(opts);
202                 } else {
203                         sorwakeup(last->inp_socket);
204                 }
205                 lwkt_reltoken(&last->inp_socket->so_rcv.ssb_token);
206         } else {
207                 m_freem(m);
208                 ipstat.ips_noproto++;
209                 ipstat.ips_delivered--;
210         }
211         return(IPPROTO_DONE);
212 }
213
214 /*
215  * Generate IP header and pass packet to ip_output.
216  * Tack on options user may have setup with control call.
217  */
218 int
219 rip_output(struct mbuf *m, struct socket *so, ...)
220 {
221         struct ip *ip;
222         struct inpcb *inp = so->so_pcb;
223         __va_list ap;
224         int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
225         u_long dst;
226
227         ASSERT_NETISR0;
228
229         __va_start(ap, so);
230         dst = __va_arg(ap, u_long);
231         __va_end(ap);
232
233         /*
234          * If the user handed us a complete IP packet, use it.
235          * Otherwise, allocate an mbuf for a header and fill it in.
236          */
237         if ((inp->inp_flags & INP_HDRINCL) == 0) {
238                 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) {
239                         m_freem(m);
240                         return(EMSGSIZE);
241                 }
242                 M_PREPEND(m, sizeof(struct ip), M_WAITOK);
243                 if (m == NULL)
244                         return(ENOBUFS);
245                 ip = mtod(m, struct ip *);
246                 ip->ip_tos = inp->inp_ip_tos;
247                 ip->ip_off = 0;
248                 ip->ip_p = inp->inp_ip_p;
249                 ip->ip_len = m->m_pkthdr.len;
250                 ip->ip_src = inp->inp_laddr;
251                 ip->ip_dst.s_addr = dst;
252                 ip->ip_ttl = inp->inp_ip_ttl;
253         } else {
254                 int hlen;
255
256                 if (m->m_pkthdr.len > IP_MAXPACKET) {
257                         m_freem(m);
258                         return(EMSGSIZE);
259                 }
260                 if (m->m_len < sizeof(struct ip)) {
261                         m = m_pullup(m, sizeof(struct ip));
262                         if (m == NULL)
263                                 return ENOBUFS;
264                 }
265                 ip = mtod(m, struct ip *);
266                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
267
268                 /* Don't allow header length less than the minimum. */
269                 if (hlen < sizeof(struct ip)) {
270                         m_freem(m);
271                         return EINVAL;
272                 }
273
274                 /*
275                  * Don't allow both user specified and setsockopt options.
276                  * Don't allow packet length sizes that will crash.
277                  */
278                 if ((hlen != sizeof(struct ip) && inp->inp_options) ||
279                     ip->ip_len > m->m_pkthdr.len || ip->ip_len < hlen) {
280                         m_freem(m);
281                         return EINVAL;
282                 }
283                 if (ip->ip_id == 0)
284                         ip->ip_id = ip_newid();
285
286                 /* Prevent ip_output from overwriting header fields */
287                 flags |= IP_RAWOUTPUT;
288                 ipstat.ips_rawout++;
289         }
290
291         return ip_output(m, inp->inp_options, &inp->inp_route, flags,
292                          inp->inp_moptions, inp);
293 }
294
295 /*
296  * Raw IP socket option processing.
297  */
298 void
299 rip_ctloutput(netmsg_t msg)
300 {
301         struct socket *so = msg->base.nm_so;
302         struct sockopt *sopt = msg->ctloutput.nm_sopt;
303         struct  inpcb *inp = so->so_pcb;
304         int     error, optval;
305
306         ASSERT_NETISR0;
307
308         error = 0;
309
310         /* Get socket's owner cpuid hint */
311         if (sopt->sopt_level == SOL_SOCKET &&
312             sopt->sopt_dir == SOPT_GET &&
313             sopt->sopt_name == SO_CPUHINT) {
314                 optval = mycpuid;
315                 soopt_from_kbuf(sopt, &optval, sizeof(optval));
316                 goto done;
317         }
318
319         if (sopt->sopt_level != IPPROTO_IP) {
320                 error = EINVAL;
321                 goto done;
322         }
323
324         switch (sopt->sopt_dir) {
325         case SOPT_GET:
326                 switch (sopt->sopt_name) {
327                 case IP_HDRINCL:
328                         optval = inp->inp_flags & INP_HDRINCL;
329                         soopt_from_kbuf(sopt, &optval, sizeof optval);
330                         break;
331
332                 case IP_FW_X:
333                         error = ip_fw3_sockopt(sopt);
334                         break;
335
336                 case IP_FW_ADD: /* ADD actually returns the body... */
337                 case IP_FW_GET:
338                 case IP_FW_TBL_GET:
339                 case IP_FW_TBL_EXPIRE: /* returns # of expired addresses */
340                         error = ip_fw_sockopt(sopt);
341                         break;
342
343                 case IP_DUMMYNET_GET:
344                         error = ip_dn_sockopt(sopt);
345                         break ;
346
347                 case MRT_INIT:
348                 case MRT_DONE:
349                 case MRT_ADD_VIF:
350                 case MRT_DEL_VIF:
351                 case MRT_ADD_MFC:
352                 case MRT_DEL_MFC:
353                 case MRT_VERSION:
354                 case MRT_ASSERT:
355                 case MRT_API_SUPPORT:
356                 case MRT_API_CONFIG:
357                 case MRT_ADD_BW_UPCALL:
358                 case MRT_DEL_BW_UPCALL:
359                         error = ip_mrouter_get ? ip_mrouter_get(so, sopt) :
360                                 EOPNOTSUPP;
361                         break;
362
363                 default:
364                         ip_ctloutput(msg);
365                         /* msg invalid now */
366                         return;
367                 }
368                 break;
369
370         case SOPT_SET:
371                 switch (sopt->sopt_name) {
372                 case IP_HDRINCL:
373                         error = soopt_to_kbuf(sopt, &optval, sizeof optval,
374                                               sizeof optval);
375                         if (error)
376                                 break;
377                         if (optval)
378                                 inp->inp_flags |= INP_HDRINCL;
379                         else
380                                 inp->inp_flags &= ~INP_HDRINCL;
381                         break;
382
383                 case IP_FW_X:
384                         error = ip_fw3_sockopt(sopt);
385                         break;
386
387                 case IP_FW_ADD:
388                 case IP_FW_DEL:
389                 case IP_FW_FLUSH:
390                 case IP_FW_ZERO:
391                 case IP_FW_RESETLOG:
392                 case IP_FW_TBL_CREATE:
393                 case IP_FW_TBL_DESTROY:
394                 case IP_FW_TBL_ADD:
395                 case IP_FW_TBL_DEL:
396                 case IP_FW_TBL_FLUSH:
397                 case IP_FW_TBL_ZERO:
398                 case IP_FW_TBL_EXPIRE:
399                         error = ip_fw_sockopt(sopt);
400                         break;
401
402                 case IP_DUMMYNET_CONFIGURE:
403                 case IP_DUMMYNET_DEL:
404                 case IP_DUMMYNET_FLUSH:
405                         error = ip_dn_sockopt(sopt);
406                         break;
407
408                 case IP_RSVP_ON:
409                         error = ip_rsvp_init(so);
410                         break;
411
412                 case IP_RSVP_OFF:
413                         error = ip_rsvp_done();
414                         break;
415
416                 case IP_RSVP_VIF_ON:
417                 case IP_RSVP_VIF_OFF:
418                         error = ip_rsvp_vif ?
419                                 ip_rsvp_vif(so, sopt) : EINVAL;
420                         break;
421
422                 case MRT_INIT:
423                 case MRT_DONE:
424                 case MRT_ADD_VIF:
425                 case MRT_DEL_VIF:
426                 case MRT_ADD_MFC:
427                 case MRT_DEL_MFC:
428                 case MRT_VERSION:
429                 case MRT_ASSERT:
430                 case MRT_API_SUPPORT:
431                 case MRT_API_CONFIG:
432                 case MRT_ADD_BW_UPCALL:
433                 case MRT_DEL_BW_UPCALL:
434                         error = ip_mrouter_set ? ip_mrouter_set(so, sopt) :
435                                         EOPNOTSUPP;
436                         break;
437
438                 default:
439                         ip_ctloutput(msg);
440                         /* msg invalid now */
441                         return;
442                 }
443                 break;
444         }
445 done:
446         lwkt_replymsg(&msg->lmsg, error);
447 }
448
449 /*
450  * This function exists solely to receive the PRC_IFDOWN messages which
451  * are sent by if_down().  It looks for an ifaddr whose ifa_addr is sa,
452  * and calls in_ifadown() to remove all routes corresponding to that address.
453  * It also receives the PRC_IFUP messages from if_up() and reinstalls the
454  * interface routes.
455  */
456 void
457 rip_ctlinput(netmsg_t msg)
458 {
459         int cmd = msg->ctlinput.nm_cmd;
460         struct sockaddr *sa = msg->ctlinput.nm_arg;
461         struct in_ifaddr *ia;
462         struct in_ifaddr_container *iac;
463         struct ifnet *ifp;
464         int err;
465         int flags;
466
467         ASSERT_NETISR0;
468
469         switch (cmd) {
470         case PRC_IFDOWN:
471                 TAILQ_FOREACH(iac, &in_ifaddrheads[mycpuid], ia_link) {
472                         ia = iac->ia;
473
474                         if (ia->ia_ifa.ifa_addr == sa &&
475                             (ia->ia_flags & IFA_ROUTE)) {
476                                 /*
477                                  * in_ifscrub kills the interface route.
478                                  */
479                                 in_ifscrub(ia->ia_ifp, ia);
480                                 /*
481                                  * in_ifadown gets rid of all the rest of
482                                  * the routes.  This is not quite the right
483                                  * thing to do, but at least if we are running
484                                  * a routing process they will come back.
485                                  */
486                                 in_ifadown(&ia->ia_ifa, 0);
487                                 break;
488                         }
489                 }
490                 break;
491
492         case PRC_IFUP:
493                 ia = NULL;
494                 TAILQ_FOREACH(iac, &in_ifaddrheads[mycpuid], ia_link) {
495                         if (iac->ia->ia_ifa.ifa_addr == sa) {
496                                 ia = iac->ia;
497                                 break;
498                         }
499                 }
500                 if (ia == NULL || (ia->ia_flags & IFA_ROUTE))
501                         goto done;
502                 flags = RTF_UP;
503                 ifp = ia->ia_ifa.ifa_ifp;
504
505 #ifdef CARP
506                 /*
507                  * Don't add prefix routes for CARP interfaces.
508                  * Prefix routes creation is handled by CARP
509                  * interfaces themselves.
510                  */
511                 if (ifp->if_type == IFT_CARP)
512                         goto done;
513 #endif
514
515                 if ((ifp->if_flags & IFF_LOOPBACK) ||
516                     (ifp->if_flags & IFF_POINTOPOINT))
517                         flags |= RTF_HOST;
518
519                 err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
520                 if (err == 0)
521                         ia->ia_flags |= IFA_ROUTE;
522                 break;
523         }
524 done:
525         lwkt_replymsg(&msg->lmsg, 0);
526 }
527
528 u_long  rip_sendspace = RIPSNDQ;
529 u_long  rip_recvspace = RIPRCVQ;
530
531 SYSCTL_INT(_net_inet_raw, OID_AUTO, maxdgram, CTLFLAG_RW,
532     &rip_sendspace, 0, "Maximum outgoing raw IP datagram size");
533 SYSCTL_INT(_net_inet_raw, OID_AUTO, recvspace, CTLFLAG_RW,
534     &rip_recvspace, 0, "Maximum incoming raw IP datagram size");
535
536 static void
537 rip_attach(netmsg_t msg)
538 {
539         struct socket *so = msg->base.nm_so;
540         int proto = msg->attach.nm_proto;
541         struct pru_attach_info *ai = msg->attach.nm_ai;
542         struct inpcb *inp;
543         int error;
544
545         ASSERT_NETISR0;
546
547         inp = so->so_pcb;
548         if (inp)
549                 panic("rip_attach");
550         error = priv_check_cred(ai->p_ucred, PRIV_NETINET_RAW, NULL_CRED_OKAY);
551         if (error)
552                 goto done;
553
554         error = soreserve(so, rip_sendspace, rip_recvspace, ai->sb_rlimit);
555         if (error)
556                 goto done;
557
558         error = in_pcballoc(so, &ripcbinfo);
559         if (error == 0) {
560                 inp = (struct inpcb *)so->so_pcb;
561                 inp->inp_ip_p = proto;
562                 inp->inp_ip_ttl = ip_defttl;
563         }
564 done:
565         lwkt_replymsg(&msg->lmsg, error);
566 }
567
568 static void
569 rip_detach(netmsg_t msg)
570 {
571         struct socket *so = msg->base.nm_so;
572         struct inpcb *inp;
573
574         ASSERT_NETISR0;
575
576         inp = so->so_pcb;
577         if (inp == NULL)
578                 panic("rip_detach");
579         if (so == ip_mrouter && ip_mrouter_done)
580                 ip_mrouter_done();
581         if (ip_rsvp_force_done)
582                 ip_rsvp_force_done(so);
583         if (so == ip_rsvpd)
584                 ip_rsvp_done();
585         in_pcbdetach(inp);
586         lwkt_replymsg(&msg->lmsg, 0);
587 }
588
589 static void
590 rip_abort(netmsg_t msg)
591 {
592         /*
593          * Raw socket does not support listen(2),
594          * so this should never be called.
595          */
596         panic("rip_abort is called");
597 }
598
599 static void
600 rip_disconnect(netmsg_t msg)
601 {
602         struct socket *so = msg->base.nm_so;
603         int error;
604
605         ASSERT_NETISR0;
606
607         if (so->so_state & SS_ISCONNECTED) {
608                 soisdisconnected(so);
609                 error = 0;
610         } else {
611                 error = ENOTCONN;
612         }
613         lwkt_replymsg(&msg->lmsg, error);
614 }
615
616 static void
617 rip_bind(netmsg_t msg)
618 {
619         struct socket *so = msg->base.nm_so;
620         struct sockaddr *nam = msg->bind.nm_nam;
621         struct inpcb *inp = so->so_pcb;
622         struct sockaddr_in *addr = (struct sockaddr_in *)nam;
623         int error;
624
625         ASSERT_NETISR0;
626
627         if (nam->sa_len == sizeof(*addr)) {
628                 if (ifnet_array_isempty() ||
629                     ((addr->sin_family != AF_INET) &&
630                      (addr->sin_family != AF_IMPLINK)) ||
631                     (addr->sin_addr.s_addr != INADDR_ANY &&
632                      ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
633                         error = EADDRNOTAVAIL;
634                 } else {
635                         inp->inp_laddr = addr->sin_addr;
636                         error = 0;
637                 }
638         } else {
639                 error = EINVAL;
640         }
641         lwkt_replymsg(&msg->lmsg, error);
642 }
643
644 static void
645 rip_connect(netmsg_t msg)
646 {
647         struct socket *so = msg->base.nm_so;
648         struct sockaddr *nam = msg->connect.nm_nam;
649         struct inpcb *inp = so->so_pcb;
650         struct sockaddr_in *addr = (struct sockaddr_in *)nam;
651         int error;
652
653         ASSERT_NETISR0;
654
655         if (nam->sa_len != sizeof(*addr)) {
656                 error = EINVAL;
657         } else if (ifnet_array_isempty()) {
658                 error = EADDRNOTAVAIL;
659         } else {
660                 if ((addr->sin_family != AF_INET) &&
661                     (addr->sin_family != AF_IMPLINK)) {
662                         error = EAFNOSUPPORT;
663                 } else {
664                         inp->inp_faddr = addr->sin_addr;
665                         soisconnected(so);
666                         error = 0;
667                 }
668         }
669         lwkt_replymsg(&msg->lmsg, error);
670 }
671
672 static void
673 rip_shutdown(netmsg_t msg)
674 {
675         ASSERT_NETISR0;
676
677         socantsendmore(msg->base.nm_so);
678         lwkt_replymsg(&msg->lmsg, 0);
679 }
680
681 static void
682 rip_send(netmsg_t msg)
683 {
684         struct socket *so = msg->base.nm_so;
685         struct mbuf *m = msg->send.nm_m;
686         /*struct mbuf *control = msg->send.nm_control;*/
687         struct sockaddr *nam = msg->send.nm_addr;
688         /*int flags = msg->send.nm_flags;*/
689         struct inpcb *inp = so->so_pcb;
690         u_long dst;
691         int error;
692
693         ASSERT_NETISR0;
694
695         if (so->so_state & SS_ISCONNECTED) {
696                 if (nam) {
697                         m_freem(m);
698                         error = EISCONN;
699                 } else {
700                         dst = inp->inp_faddr.s_addr;
701                         error = rip_output(m, so, dst);
702                 }
703         } else {
704                 if (nam == NULL) {
705                         m_freem(m);
706                         error = ENOTCONN;
707                 } else {
708                         dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
709                         error = rip_output(m, so, dst);
710                 }
711         }
712         lwkt_replymsg(&msg->lmsg, error);
713 }
714
715 SYSCTL_PROC(_net_inet_raw, OID_AUTO/*XXX*/, pcblist, CTLFLAG_RD, &ripcbinfo, 1,
716             in_pcblist_range, "S,xinpcb", "List of active raw IP sockets");
717
718 struct pr_usrreqs rip_usrreqs = {
719         .pru_abort = rip_abort,
720         .pru_accept = pr_generic_notsupp,
721         .pru_attach = rip_attach,
722         .pru_bind = rip_bind,
723         .pru_connect = rip_connect,
724         .pru_connect2 = pr_generic_notsupp,
725         .pru_control = in_control_dispatch,
726         .pru_detach = rip_detach,
727         .pru_disconnect = rip_disconnect,
728         .pru_listen = pr_generic_notsupp,
729         .pru_peeraddr = in_setpeeraddr_dispatch,
730         .pru_rcvd = pr_generic_notsupp,
731         .pru_rcvoob = pr_generic_notsupp,
732         .pru_send = rip_send,
733         .pru_sense = pru_sense_null,
734         .pru_shutdown = rip_shutdown,
735         .pru_sockaddr = in_setsockaddr_dispatch,
736         .pru_sosend = sosend,
737         .pru_soreceive = soreceive
738 };