]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx_usrreq.c
Remove redundant check for chip type being PCI-X.
[FreeBSD/FreeBSD.git] / sys / netipx / ipx_usrreq.c
1 /*
2  * Copyright (c) 1995, Mike Mitchell
3  * Copyright (c) 1984, 1985, 1986, 1987, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the University of
17  *      California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *      @(#)ipx_usrreq.c
35  *
36  * $FreeBSD$
37  */
38
39 #include "opt_ipx.h"
40
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/mbuf.h>
45 #include <sys/protosw.h>
46 #include <sys/signalvar.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/sx.h>
50 #include <sys/sysctl.h>
51 #include <sys/systm.h>
52
53 #include <net/if.h>
54 #include <net/route.h>
55
56 #include <netinet/in.h>
57
58 #include <netipx/ipx.h>
59 #include <netipx/ipx_if.h>
60 #include <netipx/ipx_ip.h>
61 #include <netipx/ipx_pcb.h>
62 #include <netipx/ipx_var.h>
63
64 /*
65  * IPX protocol implementation.
66  */
67
68 static int ipxsendspace = IPXSNDQ;
69 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxsendspace, CTLFLAG_RW,
70             &ipxsendspace, 0, "");
71 static int ipxrecvspace = IPXRCVQ;
72 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
73             &ipxrecvspace, 0, "");
74
75 static  int ipx_usr_abort(struct socket *so);
76 static  int ipx_attach(struct socket *so, int proto, struct thread *td);
77 static  int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
78 static  int ipx_connect(struct socket *so, struct sockaddr *nam,
79                         struct thread *td);
80 static  int ipx_detach(struct socket *so);
81 static  int ipx_disconnect(struct socket *so);
82 static  int ipx_send(struct socket *so, int flags, struct mbuf *m,
83                      struct sockaddr *addr, struct mbuf *control, 
84                      struct thread *td);
85 static  int ipx_shutdown(struct socket *so);
86 static  int ripx_attach(struct socket *so, int proto, struct thread *td);
87 static  int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
88
89 struct  pr_usrreqs ipx_usrreqs = {
90         ipx_usr_abort, pru_accept_notsupp, ipx_attach, ipx_bind,
91         ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
92         ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
93         pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
94         ipx_sockaddr, sosend, soreceive, sopoll
95 };
96
97 struct  pr_usrreqs ripx_usrreqs = {
98         ipx_usr_abort, pru_accept_notsupp, ripx_attach, ipx_bind,
99         ipx_connect, pru_connect2_notsupp, ipx_control, ipx_detach,
100         ipx_disconnect, pru_listen_notsupp, ipx_peeraddr, pru_rcvd_notsupp,
101         pru_rcvoob_notsupp, ipx_send, pru_sense_null, ipx_shutdown,
102         ipx_sockaddr, sosend, soreceive, sopoll
103 };
104
105 /*
106  *  This may also be called for raw listeners.
107  */
108 void
109 ipx_input(m, ipxp)
110         struct mbuf *m;
111         register struct ipxpcb *ipxp;
112 {
113         register struct ipx *ipx = mtod(m, struct ipx *);
114         struct ifnet *ifp = m->m_pkthdr.rcvif;
115         struct sockaddr_ipx ipx_ipx;
116
117         if (ipxp == NULL)
118                 panic("No ipxpcb");
119         /*
120          * Construct sockaddr format source address.
121          * Stuff source address and datagram in user buffer.
122          */
123         ipx_ipx.sipx_len = sizeof(ipx_ipx);
124         ipx_ipx.sipx_family = AF_IPX;
125         ipx_ipx.sipx_addr = ipx->ipx_sna;
126         ipx_ipx.sipx_zero[0] = '\0';
127         ipx_ipx.sipx_zero[1] = '\0';
128         if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp != NULL) {
129                 register struct ifaddr *ifa;
130
131                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa != NULL; 
132                      ifa = TAILQ_NEXT(ifa, ifa_link)) {
133                         if (ifa->ifa_addr->sa_family == AF_IPX) {
134                                 ipx_ipx.sipx_addr.x_net =
135                                         IA_SIPX(ifa)->sipx_addr.x_net;
136                                 break;
137                         }
138                 }
139         }
140         ipxp->ipxp_rpt = ipx->ipx_pt;
141         if (!(ipxp->ipxp_flags & IPXP_RAWIN) ) {
142                 m->m_len -= sizeof(struct ipx);
143                 m->m_pkthdr.len -= sizeof(struct ipx);
144                 m->m_data += sizeof(struct ipx);
145         }
146         if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
147             m, (struct mbuf *)NULL) == 0)
148                 goto bad;
149         sorwakeup(ipxp->ipxp_socket);
150         return;
151 bad:
152         m_freem(m);
153 }
154
155 void
156 ipx_abort(ipxp)
157         struct ipxpcb *ipxp;
158 {
159         struct socket *so = ipxp->ipxp_socket;
160
161         ipx_pcbdisconnect(ipxp);
162         soisdisconnected(so);
163 }
164
165 /*
166  * Drop connection, reporting
167  * the specified error.
168  */
169 void
170 ipx_drop(ipxp, errno)
171         register struct ipxpcb *ipxp;
172         int errno;
173 {
174         struct socket *so = ipxp->ipxp_socket;
175
176         /*
177          * someday, in the IPX world
178          * we will generate error protocol packets
179          * announcing that the socket has gone away.
180          *
181          * XXX Probably never. IPX does not have error packets.
182          */
183         /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
184                 tp->t_state = TCPS_CLOSED;
185                 tcp_output(tp);
186         }*/
187         so->so_error = errno;
188         ipx_pcbdisconnect(ipxp);
189         soisdisconnected(so);
190 }
191
192 static int
193 ipx_output(ipxp, m0)
194         struct ipxpcb *ipxp;
195         struct mbuf *m0;
196 {
197         register struct ipx *ipx;
198         register struct socket *so;
199         register int len = 0;
200         register struct route *ro;
201         struct mbuf *m;
202         struct mbuf *mprev = NULL;
203
204         /*
205          * Calculate data length.
206          */
207         for (m = m0; m != NULL; m = m->m_next) {
208                 mprev = m;
209                 len += m->m_len;
210         }
211         /*
212          * Make sure packet is actually of even length.
213          */
214         
215         if (len & 1) {
216                 m = mprev;
217                 if ((m->m_flags & M_EXT) == 0 &&
218                         (m->m_len + m->m_data < &m->m_dat[MLEN])) {
219                         mtod(m, char*)[m->m_len++] = 0;
220                 } else {
221                         struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
222
223                         if (m1 == NULL) {
224                                 m_freem(m0);
225                                 return (ENOBUFS);
226                         }
227                         m1->m_len = 1;
228                         * mtod(m1, char *) = 0;
229                         m->m_next = m1;
230                 }
231                 m0->m_pkthdr.len++;
232         }
233
234         /*
235          * Fill in mbuf with extended IPX header
236          * and addresses and length put into network format.
237          */
238         m = m0;
239         if (ipxp->ipxp_flags & IPXP_RAWOUT) {
240                 ipx = mtod(m, struct ipx *);
241         } else {
242                 M_PREPEND(m, sizeof(struct ipx), M_DONTWAIT);
243                 if (m == NULL)
244                         return (ENOBUFS);
245                 ipx = mtod(m, struct ipx *);
246                 ipx->ipx_tc = 0;
247                 ipx->ipx_pt = ipxp->ipxp_dpt;
248                 ipx->ipx_sna = ipxp->ipxp_laddr;
249                 ipx->ipx_dna = ipxp->ipxp_faddr;
250                 len += sizeof(struct ipx);
251         }
252
253         ipx->ipx_len = htons((u_short)len);
254
255         if (ipxp->ipxp_flags & IPXP_CHECKSUM) {
256                 ipx->ipx_sum = ipx_cksum(m, len);
257         } else
258                 ipx->ipx_sum = 0xffff;
259
260         /*
261          * Output datagram.
262          */
263         so = ipxp->ipxp_socket;
264         if (so->so_options & SO_DONTROUTE)
265                 return (ipx_outputfl(m, (struct route *)NULL,
266                     (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
267         /*
268          * Use cached route for previous datagram if
269          * possible.  If the previous net was the same
270          * and the interface was a broadcast medium, or
271          * if the previous destination was identical,
272          * then we are ok.
273          *
274          * NB: We don't handle broadcasts because that
275          *     would require 3 subroutine calls.
276          */
277         ro = &ipxp->ipxp_route;
278 #ifdef ancient_history
279         /*
280          * I think that this will all be handled in ipx_pcbconnect!
281          */
282         if (ro->ro_rt != NULL) {
283                 if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
284                         /*
285                          * This assumes we have no GH type routes
286                          */
287                         if (ro->ro_rt->rt_flags & RTF_HOST) {
288                                 if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
289                                         goto re_route;
290
291                         }
292                         if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
293                                 register struct ipx_addr *dst =
294                                                 &satoipx_addr(ro->ro_dst);
295                                 dst->x_host = ipx->ipx_dna.x_host;
296                         }
297                         /* 
298                          * Otherwise, we go through the same gateway
299                          * and dst is already set up.
300                          */
301                 } else {
302                 re_route:
303                         RTFREE(ro->ro_rt);
304                         ro->ro_rt = NULL;
305                 }
306         }
307         ipxp->ipxp_lastdst = ipx->ipx_dna;
308 #endif /* ancient_history */
309         return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
310 }
311
312 int
313 ipx_ctloutput(so, sopt)
314         struct socket *so;
315         struct sockopt *sopt;
316 {
317         struct ipxpcb *ipxp = sotoipxpcb(so);
318         int mask, error, optval;
319         short soptval;
320         struct ipx ioptval;
321
322         error = 0;
323         if (ipxp == NULL)
324                 return (EINVAL);
325
326         switch (sopt->sopt_dir) {
327         case SOPT_GET:
328                 switch (sopt->sopt_name) {
329                 case SO_ALL_PACKETS:
330                         mask = IPXP_ALL_PACKETS;
331                         goto get_flags;
332
333                 case SO_HEADERS_ON_INPUT:
334                         mask = IPXP_RAWIN;
335                         goto get_flags;
336
337                 case SO_IPX_CHECKSUM:
338                         mask = IPXP_CHECKSUM;
339                         goto get_flags;
340                         
341                 case SO_HEADERS_ON_OUTPUT:
342                         mask = IPXP_RAWOUT;
343                 get_flags:
344                         soptval = ipxp->ipxp_flags & mask;
345                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
346                         break;
347
348                 case SO_DEFAULT_HEADERS:
349                         ioptval.ipx_len = 0;
350                         ioptval.ipx_sum = 0;
351                         ioptval.ipx_tc = 0;
352                         ioptval.ipx_pt = ipxp->ipxp_dpt;
353                         ioptval.ipx_dna = ipxp->ipxp_faddr;
354                         ioptval.ipx_sna = ipxp->ipxp_laddr;
355                         error = sooptcopyout(sopt, &soptval, sizeof soptval);
356                         break;
357
358                 case SO_SEQNO:
359                         error = sooptcopyout(sopt, &ipx_pexseq, 
360                                              sizeof ipx_pexseq);
361                         ipx_pexseq++;
362                         break;
363
364                 default:
365                         error = EINVAL;
366                 }
367                 break;
368
369         case SOPT_SET:
370                 switch (sopt->sopt_name) {
371                 case SO_ALL_PACKETS:
372                         mask = IPXP_ALL_PACKETS;
373                         goto set_head;
374
375                 case SO_HEADERS_ON_INPUT:
376                         mask = IPXP_RAWIN;
377                         goto set_head;
378
379                 case SO_IPX_CHECKSUM:
380                         mask = IPXP_CHECKSUM;
381
382                 case SO_HEADERS_ON_OUTPUT:
383                         mask = IPXP_RAWOUT;
384                 set_head:
385                         error = sooptcopyin(sopt, &optval, sizeof optval,
386                                             sizeof optval);
387                         if (error)
388                                 break;
389                         if (optval)
390                                 ipxp->ipxp_flags |= mask;
391                         else
392                                 ipxp->ipxp_flags &= ~mask;
393                         break;
394
395                 case SO_DEFAULT_HEADERS:
396                         error = sooptcopyin(sopt, &ioptval, sizeof ioptval,
397                                             sizeof ioptval);
398                         if (error)
399                                 break;
400                         ipxp->ipxp_dpt = ioptval.ipx_pt;
401                         break;
402 #ifdef IPXIP
403                 case SO_IPXIP_ROUTE:
404                         error = ipxip_route(so, sopt);
405                         break;
406 #endif /* IPXIP */
407 #ifdef IPTUNNEL
408 #if 0
409                 case SO_IPXTUNNEL_ROUTE:
410                         error = ipxtun_route(so, sopt);
411                         break;
412 #endif
413 #endif
414                 default:
415                         error = EINVAL;
416                 }
417                 break;
418         }
419         return (error);
420 }
421
422 static int
423 ipx_usr_abort(so)
424         struct socket *so;
425 {
426         int s;
427         struct ipxpcb *ipxp = sotoipxpcb(so);
428
429         s = splnet();
430         ipx_pcbdetach(ipxp);
431         splx(s);
432         sotryfree(so);
433         soisdisconnected(so);
434         return (0);
435 }
436
437 static int
438 ipx_attach(so, proto, td)
439         struct socket *so;
440         int proto;
441         struct thread *td;
442 {
443         int error;
444         int s;
445         struct ipxpcb *ipxp = sotoipxpcb(so);
446
447         if (ipxp != NULL)
448                 return (EINVAL);
449         s = splnet();
450         error = ipx_pcballoc(so, &ipxpcb, td);
451         splx(s);
452         if (error == 0)
453                 error = soreserve(so, ipxsendspace, ipxrecvspace);
454         return (error);
455 }
456
457 static int
458 ipx_bind(so, nam, td)
459         struct socket *so;
460         struct sockaddr *nam;
461         struct thread *td;
462 {
463         struct ipxpcb *ipxp = sotoipxpcb(so);
464
465         return (ipx_pcbbind(ipxp, nam, td));
466 }
467
468 static int
469 ipx_connect(so, nam, td)
470         struct socket *so;
471         struct sockaddr *nam;
472         struct thread *td;
473 {
474         int error;
475         int s;
476         struct ipxpcb *ipxp = sotoipxpcb(so);
477
478         if (!ipx_nullhost(ipxp->ipxp_faddr))
479                 return (EISCONN);
480         s = splnet();
481         error = ipx_pcbconnect(ipxp, nam, td);
482         splx(s);
483         if (error == 0)
484                 soisconnected(so);
485         return (error);
486 }
487
488 static int
489 ipx_detach(so)
490         struct socket *so;
491 {
492         int s;
493         struct ipxpcb *ipxp = sotoipxpcb(so);
494
495         if (ipxp == NULL)
496                 return (ENOTCONN);
497         s = splnet();
498         ipx_pcbdetach(ipxp);
499         splx(s);
500         return (0);
501 }
502
503 static int
504 ipx_disconnect(so)
505         struct socket *so;
506 {
507         int s;
508         struct ipxpcb *ipxp = sotoipxpcb(so);
509
510         if (ipx_nullhost(ipxp->ipxp_faddr))
511                 return (ENOTCONN);
512         s = splnet();
513         ipx_pcbdisconnect(ipxp);
514         splx(s);
515         soisdisconnected(so);
516         return (0);
517 }
518
519 int
520 ipx_peeraddr(so, nam)
521         struct socket *so;
522         struct sockaddr **nam;
523 {
524         struct ipxpcb *ipxp = sotoipxpcb(so);
525
526         ipx_setpeeraddr(ipxp, nam); /* XXX what if alloc fails? */
527         return (0);
528 }
529
530 static int
531 ipx_send(so, flags, m, nam, control, td)
532         struct socket *so;
533         int flags;
534         struct mbuf *m;
535         struct sockaddr *nam;
536         struct mbuf *control;
537         struct thread *td;
538 {
539         int error;
540         struct ipxpcb *ipxp = sotoipxpcb(so);
541         struct ipx_addr laddr;
542         int s = 0;
543
544         if (nam != NULL) {
545                 laddr = ipxp->ipxp_laddr;
546                 if (!ipx_nullhost(ipxp->ipxp_faddr)) {
547                         error = EISCONN;
548                         goto send_release;
549                 }
550                 /*
551                  * Must block input while temporarily connected.
552                  */
553                 s = splnet();
554                 error = ipx_pcbconnect(ipxp, nam, td);
555                 if (error) {
556                         splx(s);
557                         goto send_release;
558                 }
559         } else {
560                 if (ipx_nullhost(ipxp->ipxp_faddr)) {
561                         error = ENOTCONN;
562                         goto send_release;
563                 }
564         }
565         error = ipx_output(ipxp, m);
566         m = NULL;
567         if (nam != NULL) {
568                 ipx_pcbdisconnect(ipxp);
569                 splx(s);
570                 ipxp->ipxp_laddr = laddr;
571         }
572
573 send_release:
574         if (m != NULL)
575                 m_freem(m);
576         return (error);
577 }
578
579 static int
580 ipx_shutdown(so)
581         struct socket *so;
582 {
583         socantsendmore(so);
584         return (0);
585 }
586
587 int
588 ipx_sockaddr(so, nam)
589         struct socket *so;
590         struct sockaddr **nam;
591 {
592         struct ipxpcb *ipxp = sotoipxpcb(so);
593
594         ipx_setsockaddr(ipxp, nam); /* XXX what if alloc fails? */
595         return (0);
596 }
597
598 static int
599 ripx_attach(so, proto, td)
600         struct socket *so;
601         int proto;
602         struct thread *td;
603 {
604         int error = 0;
605         int s;
606         struct ipxpcb *ipxp = sotoipxpcb(so);
607
608         if (td != NULL && (error = suser(td)) != 0)
609                 return (error);
610         s = splnet();
611         error = ipx_pcballoc(so, &ipxrawpcb, td);
612         splx(s);
613         if (error)
614                 return (error);
615         error = soreserve(so, ipxsendspace, ipxrecvspace);
616         if (error)
617                 return (error);
618         ipxp = sotoipxpcb(so);
619         ipxp->ipxp_faddr.x_host = ipx_broadhost;
620         ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
621         return (error);
622 }