Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
8.  STREAMS Kernel-Level Mechanisms Driver and Module Service Interfaces Service Interface Library Example Module Service Interface Example  Previous   Contents   Next 
   
 
state

Current state of the service provider IDLE or BOUND.

addr

Network address that has been bound to this stream.

The module open procedure is assumed to have set the write queue q_ptr to point at the appropriate private data structure, although this is not shown explicitly.

Service Interface Procedure

The write put procedure, protowput(), is shown in the following example:


Example 8-18 Service Interface protoput Procedure

static int protowput(queue_t *q, mblk_t *mp)
{
 	union primitives *proto;
 	struct dgproto *dgproto;
 	int err;
 	dgproto = (struct dgproto *) q->q_ptr;  /* priv data struct */
 	switch (mp->b_datap->db_type) {
 	default:
 			/* don't understand it */
 			mp->b_datap->db_type = M_ERROR;
 			mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
 			*mp->b_wptr++ = EPROTO;
 			qreply(q, mp);
 			break;
 	case M_FLUSH: /* standard flush handling goes here ... */
 			break;
 	case M_PROTO:
 			/* Protocol message -> user request */
 			proto = (union primitives *) mp->b_rptr;
 			switch (proto->type) {
 			default:
 				mp->b_datap->db_type = M_ERROR;
 				mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
 				*mp->b_wptr++ = EPROTO;
 				qreply(q, mp);
 				return;
 			case BIND_REQ:
 				if (dgproto->state != IDLE) {
 						err = EINVAL;
 						goto error_ack;
 				}
 				if (mp->b_wptr - mp->b_rptr !=
 				 sizeof(struct bind_req)) {
 						err = EINVAL;
 						goto error_ack;
 				}
 				if (err = chkaddr(proto->bind_req.BIND_addr))
 						goto error_ack;
 				dgproto->state = BOUND;
 				dgproto->addr = proto->bind_req.BIND_addr;
 				mp->b_datap->db_type = M_PCPROTO;
 				proto->type = OK_ACK;
 				mp->b_wptr=mp->b_rptr+sizeof(structok_ack);
 				qreply(q, mp);
 				break;
			error_ack:
 				mp->b_datap->db_type = M_PCPROTO;
 				proto->type = ERROR_ACK;
 				proto->error_ack.UNIX_error = err;
 				mp->b_wptr = mp->b_rptr+sizeof(structerror_ack);
 				qreply(q, mp);
 				break;
 			case UNITDATA_REQ:
 				if (dgproto->state != BOUND)
 						goto bad;
 				if (mp->b_wptr - mp->b_rptr !=
 					 sizeof(struct unitdata_req))
 						goto bad;
 				if(err=chkaddr(proto->unitdata_req.DEST_addr))
 						goto bad;
 				putq(q, mp);
 				/* start device or mux output ... */
 				break;
 			bad:
 				freemsg(mp);
 				break;
 			}
	 }
return(0);
}

The write put procedure, protowput(), switches on the message type. The only types accepted are M_FLUSH and M_PROTO. For M_FLUSH messages, the driver performs the canonical flush handling (not shown). For M_PROTO messages, the driver assumes that the message block contains a union primitive and switches on the type field. Two types are understood: BIND_REQ and UNITDATA_REQ.

For a BIND_REQ, the current state is checked; it must be IDLE. Next, the message size is checked. If it is the correct size, the passed-in address is verified for legality by calling chkaddr. If everything checks, the incoming message is converted into an OK_ACK and sent upstream. If there was any error, the incoming message is converted into an ERROR_ACK and sent upstream.

For UNITDATA_REQ, the state is also checked; it must be BOUND. As above, the message size and destination address are checked. If there is any error, the message is discarded. If all is well, the message is put in the queue, and the lower half of the driver is started.

If the write put procedure receives a message type that it does not understand, either a bad b_datap->db_type or bad proto->type, the message is converted into an M_ERROR message and is then sent upstream.

The generation of UNITDATA_IND messages (not shown in the example) would normally occur in the device interrupt if this is a hardware driver or in the lower read put procedure if this is a multiplexer. The algorithm is simple: the data part of the message is prefixed by an M_PROTO message block that contains a unitdata_ind structure and is sent upstream.

Message Type Change Rules

To change a message type, use the following rules:

  • You can only change the M_IOCTL family of message types to other M_IOCTL message types.

  • M_DATA, M_PROTO, and M_PCPROTO are dependent on the modules, driver and service provider interfaces defined.

  • A message type should not be changed if the reference count > 1.

  • The data of a message should not be modified if the reference count > 1.

  • All other message types are interchangeable as long as sufficient space has been allocated in the data buffer of the message.

 
 
 
  Previous   Contents   Next