1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)clnp_raw.c 8.1 (Berkeley) 06/10/93
8 */
9
10 /***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30
31 ******************************************************************/
32
33 /*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
36 /* $Header: clnp_raw.c,v 4.2 88/06/29 14:58:56 hagens Exp $ */
37 /* $Source: /usr/argo/sys/netiso/RCS/clnp_raw.c,v $ */
38
39 #include <sys/param.h>
40 #include <sys/mbuf.h>
41 #include <sys/domain.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47
48 #include <net/if.h>
49 #include <net/route.h>
50 #include <net/raw_cb.h>
51
52 #include <netiso/iso.h>
53 #include <netiso/iso_pcb.h>
54 #include <netiso/clnp.h>
55 #include <netiso/clnp_stat.h>
56 #include <netiso/argo_debug.h>
57
58 #include <netiso/tp_user.h> /* XXX -- defines SOL_NETWORK */
59
60 struct sockproto rclnp_proto = { PF_ISO, 0 };
61 /*
62 * FUNCTION: rclnp_input
63 *
64 * PURPOSE: Setup generic address an protocol structures for
65 * raw input routine, then pass them along with the
66 * mbuf chain.
67 *
68 * RETURNS: none
69 *
70 * SIDE EFFECTS:
71 *
72 * NOTES: The protocol field of rclnp_proto is set to zero indicating
73 * no protocol.
74 */
75 rclnp_input(m, src, dst, hdrlen)
76 struct mbuf *m; /* ptr to packet */
77 struct sockaddr_iso *src; /* ptr to src address */
78 struct sockaddr_iso *dst; /* ptr to dest address */
79 int hdrlen; /* length (in bytes) of clnp header */
80 {
81 #ifdef TROLL
82 if (trollctl.tr_ops & TR_CHUCK) {
83 m_freem(m);
84 return;
85 }
86 #endif /* TROLL */
87
88 raw_input(m, &rclnp_proto, (struct sockaddr *)src, (struct sockaddr *)dst);
89 }
90
91 /*
92 * FUNCTION: rclnp_output
93 *
94 * PURPOSE: Prepare to send a raw clnp packet. Setup src and dest
95 * addresses, count the number of bytes to send, and
96 * call clnp_output.
97 *
98 * RETURNS: success - 0
99 * failure - an appropriate error code
100 *
101 * SIDE EFFECTS:
102 *
103 * NOTES:
104 */
105 rclnp_output(m0, so)
106 struct mbuf *m0; /* packet to send */
107 struct socket *so; /* socket to send from */
108 {
109 register struct mbuf *m; /* used to scan a chain */
110 int len = 0; /* store length of chain here */
111 struct rawisopcb *rp = sotorawisopcb(so); /* ptr to raw cb */
112 int error; /* return value of function */
113 int flags; /* flags for clnp_output */
114
115 if (0 == (m0->m_flags & M_PKTHDR))
116 return (EINVAL);
117 /*
118 * Set up src address. If user has bound socket to an address, use it.
119 * Otherwise, do not specify src (clnp_output will fill it in).
120 */
121 if (rp->risop_rcb.rcb_laddr) {
122 if (rp->risop_isop.isop_sladdr.siso_family != AF_ISO) {
123 bad:
124 m_freem(m0);
125 return(EAFNOSUPPORT);
126 }
127 }
128 /* set up dest address */
129 if (rp->risop_rcb.rcb_faddr == 0)
130 goto bad;
131 rp->risop_isop.isop_sfaddr =
132 *(struct sockaddr_iso *)rp->risop_rcb.rcb_faddr;
133 rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr;
134
135 /* get flags and ship it off */
136 flags = rp->risop_flags & CLNP_VFLAGS;
137
138 error = clnp_output(m0, &rp->risop_isop, m0->m_pkthdr.len,
139 flags|CLNP_NOCACHE);
140
141 return (error);
142 }
143
144 /*
145 * FUNCTION: rclnp_ctloutput
146 *
147 * PURPOSE: Raw clnp socket option processing
148 * All options are stored inside an mbuf.
149 *
150 * RETURNS: success - 0
151 * failure - unix error code
152 *
153 * SIDE EFFECTS: If the options mbuf does not exist, it the mbuf passed
154 * is used.
155 *
156 * NOTES:
157 */
rclnp_ctloutput(op,so,level,optname,m)158 rclnp_ctloutput(op, so, level, optname, m)
159 int op; /* type of operation */
160 struct socket *so; /* ptr to socket */
161 int level; /* level of option */
162 int optname; /* name of option */
163 struct mbuf **m; /* ptr to ptr to option data */
164 {
165 int error = 0;
166 register struct rawisopcb *rp = sotorawisopcb(so);/* raw cb ptr */
167
168 IFDEBUG(D_CTLOUTPUT)
169 printf("rclnp_ctloutput: op = x%x, level = x%x, name = x%x\n",
170 op, level, optname);
171 if (*m != NULL) {
172 printf("rclnp_ctloutput: %d bytes of mbuf data\n", (*m)->m_len);
173 dump_buf(mtod((*m), caddr_t), (*m)->m_len);
174 }
175 ENDDEBUG
176
177 #ifdef SOL_NETWORK
178 if (level != SOL_NETWORK)
179 error = EINVAL;
180 else switch (op) {
181 #else
182 switch (op) {
183 #endif /* SOL_NETWORK */
184 case PRCO_SETOPT:
185 switch (optname) {
186 case CLNPOPT_FLAGS: {
187 u_short usr_flags;
188 /*
189 * Insure that the data passed has exactly one short in it
190 */
191 if ((*m == NULL) || ((*m)->m_len != sizeof(short))) {
192 error = EINVAL;
193 break;
194 }
195
196 /*
197 * Don't allow invalid flags to be set
198 */
199 usr_flags = (*mtod((*m), short *));
200
201 if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) {
202 error = EINVAL;
203 } else
204 rp->risop_flags |= usr_flags;
205
206 } break;
207
208 case CLNPOPT_OPTS:
209 if (error = clnp_set_opts(&rp->risop_isop.isop_options, m))
210 break;
211 rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS);
212 (void) clnp_opt_sanity(rp->risop_isop.isop_options,
213 mtod(rp->risop_isop.isop_options, caddr_t),
214 rp->risop_isop.isop_options->m_len,
215 mtod(rp->risop_isop.isop_optindex,
216 struct clnp_optidx *));
217 break;
218 }
219 break;
220
221 case PRCO_GETOPT:
222 #ifdef notdef
223 /* commented out to keep hi C quiet */
224 switch (optname) {
225 default:
226 error = EINVAL;
227 break;
228 }
229 #endif /* notdef */
230 break;
231 default:
232 error = EINVAL;
233 break;
234 }
235 if (op == PRCO_SETOPT) {
236 /* note: m_freem does not barf is *m is NULL */
237 m_freem(*m);
238 *m = NULL;
239 }
240
241 return error;
242 }
243
244 /*ARGSUSED*/
clnp_usrreq(so,req,m,nam,control)245 clnp_usrreq(so, req, m, nam, control)
246 register struct socket *so;
247 int req;
248 struct mbuf *m, *nam, *control;
249 {
250 register int error = 0;
251 register struct rawisopcb *rp = sotorawisopcb(so);
252
253 rp = sotorawisopcb(so);
254 switch (req) {
255
256 case PRU_ATTACH:
257 if (rp)
258 panic("rip_attach");
259 MALLOC(rp, struct rawisopcb *, sizeof *rp, M_PCB, M_WAITOK);
260 if (rp == 0)
261 return (ENOBUFS);
262 bzero((caddr_t)rp, sizeof *rp);
263 so->so_pcb = (caddr_t)rp;
264 break;
265
266 case PRU_DETACH:
267 if (rp == 0)
268 panic("rip_detach");
269 if (rp->risop_isop.isop_options)
270 m_freem(rp->risop_isop.isop_options);
271 if (rp->risop_isop.isop_route.ro_rt)
272 RTFREE(rp->risop_isop.isop_route.ro_rt);
273 if (rp->risop_rcb.rcb_laddr)
274 rp->risop_rcb.rcb_laddr = 0;
275 /* free clnp cached hdr if necessary */
276 if (rp->risop_isop.isop_clnpcache != NULL) {
277 struct clnp_cache *clcp =
278 mtod(rp->risop_isop.isop_clnpcache, struct clnp_cache *);
279 if (clcp->clc_hdr != NULL) {
280 m_free(clcp->clc_hdr);
281 }
282 m_free(rp->risop_isop.isop_clnpcache);
283 }
284 if (rp->risop_isop.isop_optindex != NULL)
285 m_free(rp->risop_isop.isop_optindex);
286
287 break;
288
289 case PRU_BIND:
290 {
291 struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *);
292
293 if (nam->m_len != sizeof(*addr))
294 return (EINVAL);
295 if ((ifnet == 0) ||
296 (addr->siso_family != AF_ISO) ||
297 (addr->siso_addr.isoa_len &&
298 ifa_ifwithaddr((struct sockaddr *)addr) == 0))
299 return (EADDRNOTAVAIL);
300 rp->risop_isop.isop_sladdr = *addr;
301 rp->risop_rcb.rcb_laddr = (struct sockaddr *)
302 (rp->risop_isop.isop_laddr = &rp->risop_isop.isop_sladdr);
303 return (0);
304 }
305 case PRU_CONNECT:
306 {
307 struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *);
308
309 if ((nam->m_len > sizeof(*addr)) || (addr->siso_len > sizeof(*addr)))
310 return (EINVAL);
311 if (ifnet == 0)
312 return (EADDRNOTAVAIL);
313 if (addr->siso_family != AF_ISO)
314 rp->risop_isop.isop_sfaddr = *addr;
315 rp->risop_rcb.rcb_faddr = (struct sockaddr *)
316 (rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr);
317 soisconnected(so);
318 return (0);
319 }
320 }
321 error = raw_usrreq(so, req, m, nam, control);
322
323 if (error && req == PRU_ATTACH && so->so_pcb)
324 free((caddr_t)rp, M_PCB);
325 return (error);
326 }
327