1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)clnp_raw.c 7.12 (Berkeley) 06/04/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 */ 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*/ 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