4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/errno.h>
32 #include <sys/cmn_err.h>
33 #include <sys/modctl.h>
37 #include <sys/callb.h>
38 #include <sys/strlog.h>
39 #include <sys/lom_io.h>
43 #include <netinet/in.h>
44 #include <sys/inttypes.h>
47 #include <sys/sunddi.h>
48 #include <sys/sunldi.h>
52 #define MIN(x, y) ((x) < (y) ? (x) : (y))
55 #define MAX(x, y) ((x) > (y) ? (x) : (y))
58 #define ABS(x) ((x) < (0) ? (-(x)) : (x))
61 #define LOMIOCALCTL_OLD _IOW('a', 4, ts_aldata_t)
62 #define LOMIOCALSTATE_OLD _IOWR('a', 5, ts_aldata_t)
64 #define PCP_CKSUM_ENABLE
65 #define PCP_DEF_MTU_SZ 100
67 #define PCP_MAX_TRY_CNT 5
68 #define PCP_GLVC_SLEEP 5
69 #define PCP_COMM_TIMEOUT 0x10
71 #define PCP_IO_OP_READ (1)
72 #define PCP_IO_OP_WRITE (2)
73 #define PCP_IO_OP_PEEK (3)
76 /* Error codes for 'status' field in response message header */
77 #define TSAL_PCP_ERROR (-1)
78 #define TSAL_PCP_OK (0) /* message received okay */
81 * magic number for Platform Channel Protocol (PCP)
82 * ~(rot13("PCP_") = 0xAFBCAFA0
83 * rot13 is a simple Caesar-cypher encryption that replaces each English letter
84 * with the one 13 places forward or back along the alphabet.
86 #define PCP_MAGIC_NUM (0xAFBCAFA0)
88 /* Platform channel protocol versions. */
89 #define PCP_PROT_VER_1 1
91 /* defines for 'timeout' */
92 #define PCP_TO_NO_RESPONSE (0xFFFFFFFF) /* no response required */
93 #define PCP_TO_WAIT_FOREVER (0) /* wait forever..(in reality, */
94 /* it waits until glvc driver */
95 /* call returns; curently glvc */
96 /* calls are blocking calls. */
99 #define PCP_ALARM_CONTROL 15
100 #define PCP_ALARM_CONTROL_R 16
103 #define PCP_ALARM_ENABLE 1
104 #define PCP_ALARM_DISABLE 2
105 #define PCP_ALARM_STATUS 3
108 #define PCP_ALARM_CRITICAL 0
109 #define PCP_ALARM_MAJOR 1
110 #define PCP_ALARM_MINOR 2
111 #define PCP_ALARM_USER 3
114 #define ALARM_STATE_ON 1
115 #define ALARM_STATE_OFF 2
116 #define ALARM_STATE_UNKNOWN 3
119 #define PCP_ALARM_OK (1)
120 #define PCP_ALARM_ERROR (2)
122 /* tsalarm service channel */
123 #define ALARM_CHANNEL "/devices/virtual-devices@100/telco-alarm@f:glvc"
125 /* Driver state flags */
126 #define TSAL_OPENED 0x1
127 #define TSAL_IDENTED 0x2
130 * Platform Channel Request Message Header.
132 typedef struct tsal_pcp_req_msg_hdr
{
133 uint32_t magic_num
; /* magic number */
134 uint8_t proto_ver
; /* version info for */
135 /* backward compatibility */
136 uint8_t msg_type
; /* provided by user apps */
137 uint8_t sub_type
; /* provided by user apps */
138 uint8_t rsvd_pad
; /* padding bits */
139 uint32_t xid
; /* transaction id */
140 uint32_t timeout
; /* timeout in seconds */
141 uint32_t msg_len
; /* length of request or response data */
142 uint16_t msg_cksum
; /* 16-bit checksum of req msg data */
143 uint16_t hdr_cksum
; /* 16-bit checksum of req hdr */
144 } tsal_pcp_req_msg_hdr_t
;
147 * Platform Channel Response Message Header.
149 typedef struct tsal_pcp_resp_msg_hdr
{
150 uint32_t magic_num
; /* magic number */
151 uint8_t proto_ver
; /* version info for */
152 /* backward compatibility */
153 uint8_t msg_type
; /* passed to user apps */
154 uint8_t sub_type
; /* passed to user apps */
155 uint8_t rsvd_pad
; /* for padding */
156 uint32_t xid
; /* transaction id */
157 uint32_t timeout
; /* timeout in seconds */
158 uint32_t msg_len
; /* length of request or response data */
159 uint32_t status
; /* response status */
160 uint16_t msg_cksum
; /* 16-bit checksum of resp msg data */
161 uint16_t hdr_cksum
; /* 16-bit checksum of resp hdr */
162 } tsal_pcp_resp_msg_hdr_t
;
165 * PCP user apps message format
167 typedef struct tsal_pcp_msg
{
176 * alarm set/get request message
178 typedef struct tsal_pcp_alarm_req
{
180 uint32_t alarm_action
;
181 } tsal_pcp_alarm_req_t
;
184 * alarm set/get response message
186 typedef struct tsal_pcp_alarm_resp
{
189 uint32_t alarm_state
;
190 } tsal_pcp_alarm_resp_t
;
193 * tsalarm driver soft structure
195 typedef struct tsalarm_softc
{
208 uint8_t *peek_read_area
;
209 tsal_pcp_alarm_req_t
*req_ptr
;
210 tsal_pcp_alarm_resp_t
*resp_ptr
;
211 tsal_pcp_req_msg_hdr_t
*req_msg_hdr
;
212 tsal_pcp_resp_msg_hdr_t
*resp_msg_hdr
;
216 * Forward declarations.
218 static int tsal_pcp_send_req_msg_hdr(tsalarm_softc_t
*sc
,
219 tsal_pcp_req_msg_hdr_t
*req_hdr
);
220 static int tsal_pcp_recv_resp_msg_hdr(tsalarm_softc_t
*sc
,
221 tsal_pcp_resp_msg_hdr_t
*resp_hdr
);
222 static int tsal_pcp_io_op(tsalarm_softc_t
*sc
, void *buf
,
223 int byte_cnt
, int io_op
);
224 static int tsal_pcp_read(tsalarm_softc_t
*sc
, uint8_t *buf
, int buf_len
);
225 static int tsal_pcp_write(tsalarm_softc_t
*sc
, uint8_t *buf
, int buf_len
);
226 static int tsal_pcp_peek(tsalarm_softc_t
*sc
, uint8_t *buf
, int buf_len
);
227 static int tsal_pcp_peek_read(tsalarm_softc_t
*sc
, uint8_t *buf
, int buf_len
);
228 static int tsal_pcp_frame_error_handle(tsalarm_softc_t
*sc
);
229 static int check_magic_byte_presence(tsalarm_softc_t
*sc
, int byte_cnt
,
230 uint8_t *byte_val
, int *ispresent
);
231 static int tsal_pcp_send_recv(tsalarm_softc_t
*sc
, tsal_pcp_msg_t
*req_msg
,
232 tsal_pcp_msg_t
*resp_msg
, uint32_t timeout
);
233 static uint32_t tsal_pcp_get_xid(tsalarm_softc_t
*sc
);
234 static uint16_t checksum(uint16_t *addr
, int32_t count
);
235 static int glvc_alarm_get(int alarm_type
, int *alarm_state
,
236 tsalarm_softc_t
*sc
);
237 static int glvc_alarm_set(int alarm_type
, int new_state
,
238 tsalarm_softc_t
*sc
);
240 #define getsoftc(minor) \
241 ((struct tsalarm_softc *)ddi_get_soft_state(statep, (minor)))
244 * Driver entry points
247 /* dev_ops and cb_ops entry point function declarations */
249 static int tsalarm_attach(dev_info_t
*, ddi_attach_cmd_t
);
250 static int tsalarm_detach(dev_info_t
*, ddi_detach_cmd_t
);
251 static int tsalarm_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
253 static int tsalarm_open(dev_t
*, int, int, cred_t
*);
254 static int tsalarm_close(dev_t
, int, int, cred_t
*);
255 static int tsalarm_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
257 static struct cb_ops tsalarm_cb_ops
= {
258 tsalarm_open
, /* open */
259 tsalarm_close
, /* close */
260 nodev
, /* strategy() */
265 tsalarm_ioctl
, /* ioctl() */
266 nodev
, /* devmap() */
268 ddi_segmap
, /* segmap() */
269 nochpoll
, /* poll() */
270 ddi_prop_op
, /* prop_op() */
272 D_NEW
| D_MP
/* cb_flag */
276 static struct dev_ops tsalarm_ops
= {
279 tsalarm_getinfo
, /* getinfo() */
280 nulldev
, /* identify() */
281 nulldev
, /* probe() */
282 tsalarm_attach
, /* attach() */
283 tsalarm_detach
, /* detach */
285 &tsalarm_cb_ops
, /* pointer to cb_ops structure */
287 nulldev
, /* power() */
288 ddi_quiesce_not_needed
, /* quiesce() */
292 * Loadable module support.
294 extern struct mod_ops mod_driverops
;
297 static struct modldrv modldrv
= {
298 &mod_driverops
, /* Type of module. This is a driver */
299 "tsalarm control driver", /* Name of the module */
300 &tsalarm_ops
/* pointer to the dev_ops structure */
303 static struct modlinkage modlinkage
= {
314 if (e
= ddi_soft_state_init(&statep
,
315 sizeof (struct tsalarm_softc
), 1)) {
319 if ((e
= mod_install(&modlinkage
)) != 0) {
320 ddi_soft_state_fini(&statep
);
331 if ((e
= mod_remove(&modlinkage
)) != 0) {
335 ddi_soft_state_fini(&statep
);
337 return (DDI_SUCCESS
);
341 _info(struct modinfo
*modinfop
)
343 return (mod_info(&modlinkage
, modinfop
));
349 tsalarm_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
351 int inst
= getminor((dev_t
)arg
);
352 int retval
= DDI_SUCCESS
;
353 struct tsalarm_softc
*softc
;
357 case DDI_INFO_DEVT2DEVINFO
:
358 if ((softc
= getsoftc(inst
)) == NULL
) {
360 retval
= DDI_FAILURE
;
362 *result
= (void *)softc
->dip
;
366 case DDI_INFO_DEVT2INSTANCE
:
367 *result
= (void *)(uintptr_t)inst
;
371 retval
= DDI_FAILURE
;
378 tsalarm_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
382 struct tsalarm_softc
*softc
= NULL
;
387 inst
= ddi_get_instance(dip
);
389 * Allocate a soft state structure for this instance.
391 if (ddi_soft_state_zalloc(statep
, inst
) != DDI_SUCCESS
) {
392 cmn_err(CE_WARN
, "Failed to allocate memory");
396 softc
= getsoftc(inst
);
398 softc
->mtu_size
= PCP_DEF_MTU_SZ
;
400 softc
->read_area
= NULL
;
401 softc
->read_head
= NULL
;
402 softc
->read_tail
= NULL
;
403 softc
->req_ptr
= NULL
;
404 softc
->resp_ptr
= NULL
;
406 mutex_init(&softc
->mutex
, NULL
, MUTEX_DRIVER
, NULL
);
408 * Create minor node. The minor device number, inst, has no
409 * meaning. The model number above, which will be added to
410 * the device's softc, is used to direct peculiar behavior.
412 if (ddi_create_minor_node(dip
, "lom", S_IFCHR
, 0,
413 DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
418 return (DDI_SUCCESS
);
421 return (DDI_SUCCESS
);
424 return (DDI_FAILURE
);
428 /* Free soft state, if allocated. remove minor node if added earlier */
430 mutex_destroy(&softc
->mutex
);
431 ddi_soft_state_free(statep
, inst
);
434 ddi_remove_minor_node(dip
, NULL
);
436 return (DDI_FAILURE
);
440 tsalarm_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
443 struct tsalarm_softc
*softc
;
448 inst
= ddi_get_instance(dip
);
449 if ((softc
= getsoftc(inst
)) == NULL
)
450 return (DDI_FAILURE
);
452 * Free the soft state and remove minor node added earlier.
454 ddi_remove_minor_node(dip
, NULL
);
455 mutex_destroy(&softc
->mutex
);
456 ddi_soft_state_free(statep
, inst
);
457 return (DDI_SUCCESS
);
460 return (DDI_SUCCESS
);
463 return (DDI_FAILURE
);
470 tsalarm_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*credp
)
472 int rv
, inst
= getminor(*devp
);
473 struct tsalarm_softc
*softc
;
474 glvc_xport_opt_op_t channel_op
;
477 softc
= (struct tsalarm_softc
*)getsoftc(inst
);
479 cmn_err(CE_WARN
, "getsoftc failed\n");
483 mutex_enter(&softc
->mutex
);
485 rv
= ldi_ident_from_dev(*devp
, &softc
->li
);
487 cmn_err(CE_WARN
, "ldi_ident_from_dev failed\n");
490 softc
->flags
|= TSAL_IDENTED
;
492 rv
= ldi_open_by_name(ALARM_CHANNEL
, FREAD
| FWRITE
, kcred
, &softc
->lh
,
495 cmn_err(CE_WARN
, "ldi_open_by_name failed\n");
498 softc
->flags
|= TSAL_OPENED
;
500 /* Get the MTU of the target channel */
501 channel_op
.op_sel
= GLVC_XPORT_OPT_GET
;
502 channel_op
.opt_sel
= GLVC_XPORT_OPT_MTU_SZ
;
503 channel_op
.opt_val
= 0;
505 if ((rv
= ldi_ioctl(softc
->lh
, GLVC_XPORT_IOCTL_OPT_OP
,
506 (intptr_t)&channel_op
, FKIOCTL
, kcred
, &rval
)) < 0) {
507 cmn_err(CE_WARN
, "ldi_ioctl failed\n");
510 softc
->mtu_size
= channel_op
.opt_val
;
512 if ((softc
->req_ptr
= (tsal_pcp_alarm_req_t
*)kmem_zalloc(
513 sizeof (tsal_pcp_alarm_req_t
),
514 KM_NOSLEEP
)) == NULL
) {
517 if ((softc
->resp_ptr
= (tsal_pcp_alarm_resp_t
*)kmem_zalloc(
518 sizeof (tsal_pcp_alarm_resp_t
),
519 KM_NOSLEEP
)) == NULL
) {
522 if ((softc
->req_msg_hdr
= (tsal_pcp_req_msg_hdr_t
*)kmem_zalloc(
523 sizeof (tsal_pcp_req_msg_hdr_t
),
524 KM_NOSLEEP
)) == NULL
) {
527 if ((softc
->resp_msg_hdr
= (tsal_pcp_resp_msg_hdr_t
*)kmem_zalloc(
528 sizeof (tsal_pcp_resp_msg_hdr_t
),
529 KM_NOSLEEP
)) == NULL
) {
532 if ((softc
->peek_area
= kmem_zalloc(softc
->mtu_size
,
533 KM_NOSLEEP
)) == NULL
) {
536 if ((softc
->peek_read_area
= kmem_zalloc(2*softc
->mtu_size
,
537 KM_NOSLEEP
)) == NULL
) {
545 if (softc
->flags
& TSAL_OPENED
)
546 (void) ldi_close(softc
->lh
, FREAD
|FWRITE
, credp
);
547 if (softc
->flags
* TSAL_IDENTED
)
548 (void) ldi_ident_release(softc
->li
);
549 softc
->flags
&= ~(TSAL_OPENED
| TSAL_IDENTED
);
550 if (softc
->req_ptr
!= NULL
)
551 kmem_free(softc
->req_ptr
,
552 sizeof (tsal_pcp_alarm_req_t
));
553 if (softc
->resp_ptr
!= NULL
)
554 kmem_free(softc
->resp_ptr
,
555 sizeof (tsal_pcp_alarm_resp_t
));
556 if (softc
->req_msg_hdr
!= NULL
)
557 kmem_free(softc
->req_msg_hdr
,
558 sizeof (tsal_pcp_req_msg_hdr_t
));
559 if (softc
->resp_msg_hdr
!= NULL
)
560 kmem_free(softc
->resp_msg_hdr
,
561 sizeof (tsal_pcp_resp_msg_hdr_t
));
562 if (softc
->peek_area
!= NULL
)
563 kmem_free(softc
->peek_area
, softc
->mtu_size
);
564 if (softc
->peek_read_area
!= NULL
)
565 kmem_free(softc
->peek_read_area
, 2*softc
->mtu_size
);
567 mutex_exit(&softc
->mutex
);
575 tsalarm_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
577 int rv
, inst
= getminor(dev
);
578 struct tsalarm_softc
*softc
;
580 softc
= (struct tsalarm_softc
*)getsoftc(inst
);
586 mutex_enter(&softc
->mutex
);
588 rv
= ldi_close(softc
->lh
, FREAD
| FWRITE
, kcred
);
590 cmn_err(CE_WARN
, "ldi_close failed \n");
593 ldi_ident_release(softc
->li
);
594 softc
->flags
&= ~(TSAL_OPENED
| TSAL_IDENTED
);
596 mutex_exit(&softc
->mutex
);
599 * free global buffers
601 if (softc
->read_area
!= NULL
) {
602 kmem_free(softc
->read_area
, 2*softc
->mtu_size
);
603 softc
->read_area
= NULL
;
605 if (softc
->req_ptr
!= NULL
) {
606 kmem_free(softc
->req_ptr
,
607 sizeof (tsal_pcp_alarm_req_t
));
608 softc
->req_ptr
= NULL
;
610 if (softc
->resp_ptr
!= NULL
) {
611 kmem_free(softc
->resp_ptr
,
612 sizeof (tsal_pcp_alarm_resp_t
));
613 softc
->resp_ptr
= NULL
;
615 if (softc
->req_msg_hdr
!= NULL
) {
616 kmem_free(softc
->req_msg_hdr
,
617 sizeof (tsal_pcp_req_msg_hdr_t
));
618 softc
->req_msg_hdr
= NULL
;
620 if (softc
->resp_msg_hdr
!= NULL
) {
621 kmem_free(softc
->resp_msg_hdr
,
622 sizeof (tsal_pcp_resp_msg_hdr_t
));
623 softc
->resp_msg_hdr
= NULL
;
625 if (softc
->peek_area
!= NULL
) {
626 kmem_free(softc
->peek_area
, softc
->mtu_size
);
627 softc
->peek_area
= NULL
;
629 if (softc
->peek_read_area
!= NULL
) {
630 kmem_free(softc
->peek_read_area
, 2*softc
->mtu_size
);
631 softc
->peek_read_area
= NULL
;
640 tsalarm_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
641 cred_t
*credp
, int *rvalp
)
643 int inst
= getminor(dev
);
644 struct tsalarm_softc
*softc
;
646 ts_aldata_t ts_alinfo
;
647 int alarm_type
, alarm_state
= 0;
649 if ((softc
= getsoftc(inst
)) == NULL
)
652 mutex_enter(&softc
->mutex
);
657 case LOMIOCALSTATE_OLD
:
659 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ts_alinfo
,
660 sizeof (ts_aldata_t
), mode
) != 0) {
665 alarm_type
= ts_alinfo
.alarm_no
;
666 if ((alarm_type
< ALARM_CRITICAL
) ||
667 (alarm_type
> ALARM_USER
)) {
672 retval
= glvc_alarm_get(alarm_type
, &alarm_state
,
678 if ((alarm_state
!= 0) && (alarm_state
!= 1)) {
683 ts_alinfo
.alarm_state
= alarm_state
;
684 if (ddi_copyout((caddr_t
)&ts_alinfo
, (caddr_t
)arg
,
685 sizeof (ts_aldata_t
), mode
) != 0) {
693 case LOMIOCALCTL_OLD
:
695 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ts_alinfo
,
696 sizeof (ts_aldata_t
), mode
) != 0) {
701 alarm_type
= ts_alinfo
.alarm_no
;
702 alarm_state
= ts_alinfo
.alarm_state
;
704 if ((alarm_type
< ALARM_CRITICAL
) ||
705 (alarm_type
> ALARM_USER
)) {
709 if ((alarm_state
< ALARM_OFF
) ||
710 (alarm_state
> ALARM_ON
)) {
715 retval
= glvc_alarm_set(alarm_type
, alarm_state
, softc
);
725 mutex_exit(&softc
->mutex
);
731 glvc_alarm_get(int alarm_type
, int *alarm_state
, tsalarm_softc_t
*sc
)
733 tsal_pcp_alarm_req_t
*req_ptr
= NULL
;
734 tsal_pcp_alarm_resp_t
*resp_ptr
= NULL
;
735 tsal_pcp_msg_t send_msg
;
736 tsal_pcp_msg_t recv_msg
;
740 * setup the request data to attach to the libpcp msg
742 if (sc
->req_ptr
== NULL
) {
746 req_ptr
= sc
->req_ptr
;
748 req_ptr
->alarm_action
= PCP_ALARM_STATUS
;
749 req_ptr
->alarm_id
= alarm_type
;
751 send_msg
.msg_type
= PCP_ALARM_CONTROL
;
752 send_msg
.sub_type
= NULL
;
753 send_msg
.msg_len
= sizeof (tsal_pcp_alarm_req_t
);
754 send_msg
.msg_data
= (uint8_t *)req_ptr
;
757 * send the request, receive the response
759 if (tsal_pcp_send_recv(sc
, &send_msg
, &recv_msg
,
760 PCP_COMM_TIMEOUT
) < 0) {
761 /* we either timed out or erred; either way try again */
762 (void) ddi_sleep(PCP_COMM_TIMEOUT
);
764 if (tsal_pcp_send_recv(sc
, &send_msg
, &recv_msg
,
765 PCP_COMM_TIMEOUT
) < 0) {
766 cmn_err(CE_WARN
, "tsalarm: communication failure");
772 * validate that this data was meant for us
774 if (recv_msg
.msg_type
!= PCP_ALARM_CONTROL_R
) {
775 cmn_err(CE_WARN
, "tsalarm: unbound packet received");
780 * verify that the Alarm action has taken place
782 resp_ptr
= (tsal_pcp_alarm_resp_t
*)recv_msg
.msg_data
;
783 if (resp_ptr
->status
== PCP_ALARM_ERROR
) {
784 cmn_err(CE_WARN
, "tsalarm: failed to get alarm status");
788 if (resp_ptr
->alarm_state
== ALARM_STATE_UNKNOWN
)
789 cmn_err(CE_WARN
, "tsalarm: ALARM set to unknown state");
791 *alarm_state
= resp_ptr
->alarm_state
;
792 status
= TSAL_PCP_OK
;
799 glvc_alarm_set(int alarm_type
, int new_state
, tsalarm_softc_t
*sc
)
801 tsal_pcp_alarm_req_t
*req_ptr
= NULL
;
802 tsal_pcp_alarm_resp_t
*resp_ptr
= NULL
;
803 tsal_pcp_msg_t send_msg
;
804 tsal_pcp_msg_t recv_msg
;
808 * setup the request data to attach to the libpcp msg
810 if (sc
->req_ptr
== NULL
) {
811 if ((sc
->req_ptr
= (tsal_pcp_alarm_req_t
*)kmem_zalloc(
812 sizeof (tsal_pcp_alarm_req_t
),
813 KM_NOSLEEP
)) == NULL
)
817 req_ptr
= sc
->req_ptr
;
819 if (new_state
== ALARM_ON
)
820 req_ptr
->alarm_action
= PCP_ALARM_ENABLE
;
821 else if (new_state
== ALARM_OFF
)
822 req_ptr
->alarm_action
= PCP_ALARM_DISABLE
;
824 req_ptr
->alarm_id
= alarm_type
;
826 send_msg
.msg_type
= PCP_ALARM_CONTROL
;
827 send_msg
.sub_type
= NULL
;
828 send_msg
.msg_len
= sizeof (tsal_pcp_alarm_req_t
);
829 send_msg
.msg_data
= (uint8_t *)req_ptr
;
832 * send the request, receive the response
834 if (tsal_pcp_send_recv(sc
, &send_msg
, &recv_msg
,
835 PCP_COMM_TIMEOUT
) < 0) {
836 /* we either timed out or erred; either way try again */
837 (void) ddi_sleep(PCP_COMM_TIMEOUT
);
839 if (tsal_pcp_send_recv(sc
, &send_msg
, &recv_msg
,
840 PCP_COMM_TIMEOUT
) < 0) {
846 * validate that this data was meant for us
848 if (recv_msg
.msg_type
!= PCP_ALARM_CONTROL_R
) {
849 cmn_err(CE_WARN
, "tsalarm: unbound packet received");
854 * verify that the Alarm action has taken place
856 resp_ptr
= (tsal_pcp_alarm_resp_t
*)recv_msg
.msg_data
;
857 if (resp_ptr
->status
== PCP_ALARM_ERROR
) {
858 cmn_err(CE_WARN
, "tsalarm: failed to set alarm status");
863 * ensure the Alarm action taken is the one requested
865 if ((req_ptr
->alarm_action
== PCP_ALARM_DISABLE
) &&
866 (resp_ptr
->alarm_state
!= ALARM_STATE_OFF
)) {
867 cmn_err(CE_WARN
, "tsalarm: failed to set alarm");
869 } else if ((req_ptr
->alarm_action
== PCP_ALARM_ENABLE
) &&
870 (resp_ptr
->alarm_state
!= ALARM_STATE_ON
)) {
871 cmn_err(CE_WARN
, "tsalarm: failed to set alarm");
873 } else if (resp_ptr
->alarm_state
== ALARM_STATE_UNKNOWN
) {
874 cmn_err(CE_WARN
, "tsalarm: Alarm set to unknown state");
878 status
= TSAL_PCP_OK
;
884 * Function: Send and Receive messages on platform channel.
886 * int channel_fd - channel file descriptor.
887 * tsal_pcp_msg_t *req_msg - Request Message to send to other end of channel.
888 * tsal_pcp_msg_t *resp_msg - Response Message to be received.
889 * uint32_t timeout - timeout field when waiting for data from channel.
891 * 0 - success (TSAL_PCP_OK).
892 * (-1) - failure (TSAL_PCP_ERROR).
895 tsal_pcp_send_recv(tsalarm_softc_t
*sc
, tsal_pcp_msg_t
*req_msg
,
896 tsal_pcp_msg_t
*resp_msg
, uint32_t timeout
)
899 void *resp_msg_data
= NULL
;
904 tsal_pcp_req_msg_hdr_t
*req_msg_hdr
= NULL
;
905 tsal_pcp_resp_msg_hdr_t
*resp_msg_hdr
= NULL
;
906 #ifdef PCP_CKSUM_ENABLE
907 uint16_t bkup_resp_hdr_cksum
;
911 if (req_msg
== NULL
) {
912 return (TSAL_PCP_ERROR
);
915 if ((req_msg
->msg_len
!= 0) && ((datap
= req_msg
->msg_data
) == NULL
))
916 return (TSAL_PCP_ERROR
);
918 req_msg_hdr
= sc
->req_msg_hdr
;
920 if (req_msg_hdr
== NULL
)
921 return (TSAL_PCP_ERROR
);
923 if (req_msg
->msg_len
!= 0) {
924 /* calculate request msg_cksum */
925 cksum
= checksum((uint16_t *)datap
, req_msg
->msg_len
);
929 * Fill in the message header for the request packet
931 req_msg_hdr
->magic_num
= PCP_MAGIC_NUM
;
932 req_msg_hdr
->proto_ver
= PCP_PROT_VER_1
;
933 req_msg_hdr
->msg_type
= req_msg
->msg_type
;
934 req_msg_hdr
->sub_type
= req_msg
->sub_type
;
935 req_msg_hdr
->rsvd_pad
= 0;
936 req_msg_hdr
->xid
= tsal_pcp_get_xid(sc
);
937 req_msg_hdr
->msg_len
= req_msg
->msg_len
;
938 req_msg_hdr
->timeout
= timeout
;
939 req_msg_hdr
->msg_cksum
= cksum
;
940 req_msg_hdr
->hdr_cksum
= 0;
942 /* fill request header checksum */
943 req_msg_hdr
->hdr_cksum
= checksum((uint16_t *)req_msg_hdr
,
944 sizeof (tsal_pcp_req_msg_hdr_t
));
947 * send request message header
949 if ((ret
= tsal_pcp_send_req_msg_hdr(sc
, req_msg_hdr
))) {
954 * send request message
956 if (req_msg
->msg_len
!= 0) {
957 if ((ret
= tsal_pcp_io_op(sc
, datap
, req_msg
->msg_len
,
963 if (timeout
== (uint32_t)PCP_TO_NO_RESPONSE
)
964 return (TSAL_PCP_OK
);
966 resp_msg_hdr
= sc
->resp_msg_hdr
;
968 if (resp_msg_hdr
== NULL
) {
969 return (TSAL_PCP_ERROR
);
973 while (!resp_hdr_ok
) {
975 * Receive response message header
976 * Note: frame error handling is done in
977 * 'tsal_pcp_recv_resp_msg_hdr()'.
979 if ((ret
= tsal_pcp_recv_resp_msg_hdr(sc
, resp_msg_hdr
))) {
984 * Check header checksum if it matches with the received hdr
987 #ifdef PCP_CKSUM_ENABLE
988 bkup_resp_hdr_cksum
= resp_msg_hdr
->hdr_cksum
;
989 resp_msg_hdr
->hdr_cksum
= 0;
990 cksum
= checksum((uint16_t *)resp_msg_hdr
,
991 sizeof (tsal_pcp_resp_msg_hdr_t
));
993 if (cksum
!= bkup_resp_hdr_cksum
) {
994 return (TSAL_PCP_ERROR
);
998 * Check for matching request and response messages
1000 if (resp_msg_hdr
->xid
!= req_msg_hdr
->xid
) {
1001 continue; /* continue reading response header */
1007 * check status field for any channel protocol errrors
1008 * This field signifies something happend during request
1009 * message trasmission. This field is set by the receiver.
1011 status
= resp_msg_hdr
->status
;
1012 if (status
!= TSAL_PCP_OK
) {
1013 return (TSAL_PCP_ERROR
);
1016 if (resp_msg_hdr
->msg_len
!= 0) {
1017 if (sc
->resp_ptr
== NULL
)
1018 return (TSAL_PCP_ERROR
);
1020 resp_msg_data
= (uint8_t *)sc
->resp_ptr
;
1022 * Receive response message.
1024 if ((ret
= tsal_pcp_io_op(sc
, resp_msg_data
,
1025 resp_msg_hdr
->msg_len
,
1030 #ifdef PCP_CKSUM_ENABLE
1031 /* verify response message data checksum */
1032 cksum
= checksum((uint16_t *)resp_msg_data
,
1033 resp_msg_hdr
->msg_len
);
1034 if (cksum
!= resp_msg_hdr
->msg_cksum
) {
1035 return (TSAL_PCP_ERROR
);
1039 /* Everything is okay put the received data into user */
1040 /* resp_msg struct */
1041 resp_msg
->msg_len
= resp_msg_hdr
->msg_len
;
1042 resp_msg
->msg_type
= resp_msg_hdr
->msg_type
;
1043 resp_msg
->sub_type
= resp_msg_hdr
->sub_type
;
1044 resp_msg
->msg_data
= (uint8_t *)resp_msg_data
;
1046 return (TSAL_PCP_OK
);
1050 * Function: wrapper for handling glvc calls (read/write/peek).
1053 tsal_pcp_io_op(tsalarm_softc_t
*sc
, void *buf
, int byte_cnt
, int io_op
)
1058 int (*func_ptr
)(tsalarm_softc_t
*, uint8_t *, int);
1062 if ((buf
== NULL
) || (byte_cnt
< 0)) {
1063 return (TSAL_PCP_ERROR
);
1067 case PCP_IO_OP_READ
:
1068 func_ptr
= tsal_pcp_read
;
1070 case PCP_IO_OP_WRITE
:
1071 func_ptr
= tsal_pcp_write
;
1073 case PCP_IO_OP_PEEK
:
1074 func_ptr
= tsal_pcp_peek
;
1077 return (TSAL_PCP_ERROR
);
1081 * loop until all I/O done, try limit exceded, or real failure
1086 while (rv
< byte_cnt
) {
1087 io_sz
= MIN((byte_cnt
- rv
), sc
->mtu_size
);
1089 while ((n
= (*func_ptr
)(sc
, datap
, io_sz
)) < 0) {
1091 if (try_cnt
> PCP_MAX_TRY_CNT
) {
1095 /* waiting 5 secs. Do we need 5 Secs? */
1096 (void) ddi_sleep(PCP_GLVC_SLEEP
);
1097 } /* while trying the io operation */
1105 } /* while still have more data */
1111 return (TSAL_PCP_ERROR
);
1115 * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
1116 * If data is available, the data is copied into 'buf'.
1119 tsal_pcp_peek(tsalarm_softc_t
*sc
, uint8_t *buf
, int bytes_cnt
)
1122 glvc_xport_msg_peek_t peek_ctrl
;
1125 if (bytes_cnt
< 0 || bytes_cnt
> sc
->mtu_size
) {
1126 return (TSAL_PCP_ERROR
);
1130 * initialization of buffers used for peeking data in channel buffers.
1132 if (sc
->peek_area
== NULL
) {
1133 return (TSAL_PCP_ERROR
);
1137 * peek max MTU size bytes
1139 peek_ctrl
.buf
= (caddr_t
)sc
->peek_area
;
1140 peek_ctrl
.buflen
= sc
->mtu_size
;
1141 peek_ctrl
.flags
= 0;
1143 if ((ret
= ldi_ioctl(sc
->lh
, GLVC_XPORT_IOCTL_DATA_PEEK
,
1144 (intptr_t)&peek_ctrl
, FKIOCTL
, kcred
, &rval
)) < 0) {
1148 n
= peek_ctrl
.buflen
;
1151 return (TSAL_PCP_ERROR
);
1154 * satisfy request as best as we can
1156 m
= MIN(bytes_cnt
, n
);
1157 (void) memcpy(buf
, sc
->peek_area
, m
);
1163 * Function: write 'byte_cnt' bytes from 'buf' to channel.
1166 tsal_pcp_write(tsalarm_softc_t
*sc
, uint8_t *buf
, int byte_cnt
)
1172 /* check for valid arguments */
1173 if (buf
== NULL
|| byte_cnt
< 0 || byte_cnt
> sc
->mtu_size
) {
1174 return (TSAL_PCP_ERROR
);
1176 bzero(&uio
, sizeof (uio
));
1177 bzero(&iov
, sizeof (iov
));
1178 iov
.iov_base
= (int8_t *)buf
;
1179 iov
.iov_len
= byte_cnt
;
1182 uio
.uio_loffset
= 0;
1183 uio
.uio_segflg
= UIO_SYSSPACE
;
1184 uio
.uio_resid
= byte_cnt
;
1186 if ((ret
= ldi_write(sc
->lh
, &uio
, kcred
)) < 0) {
1189 return (byte_cnt
- iov
.iov_len
);
1193 * In current implementaion of glvc driver, streams reads are not supported.
1194 * tsal_pcp_read mimics stream reads by first reading all the bytes present in
1195 * channel buffer into a local buffer and from then on read requests
1196 * are serviced from local buffer. When read requests are not serviceble
1197 * from local buffer, it repeates by first reading data from channel buffers.
1201 tsal_pcp_read(tsalarm_softc_t
*sc
, uint8_t *buf
, int byte_cnt
)
1207 int read_area_size
= 0;
1209 if (byte_cnt
< 0 || byte_cnt
> sc
->mtu_size
) {
1210 return (TSAL_PCP_ERROR
);
1213 read_area_size
= 2*sc
->mtu_size
;
1215 * initialization of local read buffer
1216 * from which the stream read requests are serviced.
1218 if (sc
->read_area
== NULL
) {
1219 sc
->read_area
= kmem_zalloc(read_area_size
,
1221 if (sc
->read_area
== NULL
) {
1222 return (TSAL_PCP_ERROR
);
1224 sc
->read_head
= sc
->read_area
;
1225 sc
->read_tail
= sc
->read_area
;
1229 * if we already read this data then copy from local buffer it self
1230 * without calling new read.
1232 if (byte_cnt
<= (sc
->read_tail
- sc
->read_head
)) {
1233 (void) memcpy(buf
, sc
->read_head
, byte_cnt
);
1234 sc
->read_head
+= byte_cnt
;
1239 * if the request is not satisfied from the buffered data, then move
1240 * remaining data to front of the buffer and read new data.
1242 for (i
= 0; i
< (sc
->read_tail
- sc
->read_head
); ++i
) {
1243 sc
->read_area
[i
] = sc
->read_head
[i
];
1245 sc
->read_head
= sc
->read_area
;
1246 sc
->read_tail
= sc
->read_head
+ i
;
1249 * do a peek to see how much data is available and read complete data.
1252 if ((m
= tsal_pcp_peek(sc
, sc
->read_tail
, sc
->mtu_size
)) < 0) {
1256 bzero(&uio
, sizeof (uio
));
1257 bzero(&iov
, sizeof (iov
));
1258 iov
.iov_base
= (int8_t *)sc
->read_tail
;
1262 uio
.uio_loffset
= 0;
1263 uio
.uio_segflg
= UIO_SYSSPACE
;
1266 if ((ret
= ldi_read(sc
->lh
, &uio
, kcred
)) != 0) {
1270 sc
->read_tail
+= (m
- iov
.iov_len
);
1273 * copy the requested bytes.
1275 n
= MIN(byte_cnt
, (sc
->read_tail
- sc
->read_head
));
1276 (void) memcpy(buf
, sc
->read_head
, n
);
1283 * This function is slight different from tsal_pcp_peek. The peek requests are
1284 * serviced from local read buffer, if data is available. If the peek request
1285 * is not serviceble from local read buffer, then the data is peeked from
1286 * channel buffer. This function is mainly used for proper protocol framing
1290 tsal_pcp_peek_read(tsalarm_softc_t
*sc
, uint8_t *buf
, int byte_cnt
)
1293 uint8_t *peek_read_head
= NULL
;
1294 uint8_t *peek_read_tail
= NULL
;
1296 if (byte_cnt
< 0 || byte_cnt
> sc
->mtu_size
) {
1297 return (TSAL_PCP_ERROR
);
1301 * if we already have the data in local read buffer then copy
1302 * from local buffer it self w/out calling new peek
1304 if (byte_cnt
<= (sc
->read_tail
- sc
->read_head
)) {
1305 (void) memcpy(buf
, sc
->read_head
, byte_cnt
);
1310 if (sc
->peek_read_area
== NULL
) {
1311 return (TSAL_PCP_ERROR
);
1313 peek_read_head
= sc
->peek_read_area
;
1314 peek_read_tail
= sc
->peek_read_area
;
1317 * if the request is not satisfied from local read buffer, then first
1318 * copy the remaining data in local read buffer to peek_read_area and
1319 * then issue new peek.
1321 for (i
= 0; i
< (sc
->read_tail
- sc
->read_head
); ++i
) {
1322 sc
->peek_read_area
[i
] = sc
->read_head
[i
];
1324 peek_read_head
= sc
->peek_read_area
;
1325 peek_read_tail
= peek_read_head
+ i
;
1328 * do a peek to see how much data is available and read complete data.
1331 if ((m
= tsal_pcp_peek(sc
, peek_read_tail
, sc
->mtu_size
)) < 0) {
1335 peek_read_tail
+= m
;
1338 * copy the requested bytes
1340 n
= MIN(byte_cnt
, (peek_read_tail
- peek_read_head
));
1341 (void) memcpy(buf
, peek_read_head
, n
);
1346 * Send Request Message Header.
1349 tsal_pcp_send_req_msg_hdr(tsalarm_softc_t
*sc
, tsal_pcp_req_msg_hdr_t
*req_hdr
)
1351 tsal_pcp_req_msg_hdr_t
*hdrp
;
1355 hdr_sz
= sizeof (tsal_pcp_req_msg_hdr_t
);
1356 if ((hdrp
= (tsal_pcp_req_msg_hdr_t
*)kmem_zalloc(hdr_sz
,
1357 KM_NOSLEEP
)) == NULL
) {
1358 return (TSAL_PCP_ERROR
);
1361 hdrp
->magic_num
= htonl(req_hdr
->magic_num
);
1362 hdrp
->proto_ver
= req_hdr
->proto_ver
;
1363 hdrp
->msg_type
= req_hdr
->msg_type
;
1364 hdrp
->sub_type
= req_hdr
->sub_type
;
1365 hdrp
->rsvd_pad
= htons(req_hdr
->rsvd_pad
);
1366 hdrp
->xid
= htonl(req_hdr
->xid
);
1367 hdrp
->timeout
= htonl(req_hdr
->timeout
);
1368 hdrp
->msg_len
= htonl(req_hdr
->msg_len
);
1369 hdrp
->msg_cksum
= htons(req_hdr
->msg_cksum
);
1370 hdrp
->hdr_cksum
= htons(req_hdr
->hdr_cksum
);
1372 if ((ret
= tsal_pcp_io_op(sc
, (char *)hdrp
, hdr_sz
,
1373 PCP_IO_OP_WRITE
)) != 0) {
1374 kmem_free(hdrp
, hdr_sz
);
1377 kmem_free(hdrp
, hdr_sz
);
1378 return (TSAL_PCP_OK
);
1381 * Receive Response message header.
1384 tsal_pcp_recv_resp_msg_hdr(tsalarm_softc_t
*sc
,
1385 tsal_pcp_resp_msg_hdr_t
*resp_hdr
)
1400 if (resp_hdr
== NULL
) {
1401 return (TSAL_PCP_ERROR
);
1405 * handle protocol framing errors.
1406 * tsal_pcp_frame_error_handle() returns when proper frame arrived
1407 * (magic seq) or if an error happens while reading data from
1410 if ((ret
= tsal_pcp_frame_error_handle(sc
)) != 0) {
1411 return (TSAL_PCP_ERROR
);
1414 /* read magic number first */
1415 if ((ret
= tsal_pcp_io_op(sc
, &magic_num
, sizeof (magic_num
),
1416 PCP_IO_OP_READ
)) != 0) {
1420 magic_num
= ntohl(magic_num
);
1422 if (magic_num
!= PCP_MAGIC_NUM
) {
1423 return (TSAL_PCP_ERROR
);
1426 /* read version field */
1427 if ((ret
= tsal_pcp_io_op(sc
, &proto_ver
, sizeof (proto_ver
),
1428 PCP_IO_OP_READ
)) != 0) {
1432 /* check protocol version */
1433 if (proto_ver
!= PCP_PROT_VER_1
) {
1434 return (TSAL_PCP_ERROR
);
1437 /* Read message type */
1438 if ((ret
= tsal_pcp_io_op(sc
, &msg_type
, sizeof (msg_type
),
1439 PCP_IO_OP_READ
)) != 0) {
1443 /* Read message sub type */
1444 if ((ret
= tsal_pcp_io_op(sc
, &sub_type
, sizeof (sub_type
),
1445 PCP_IO_OP_READ
)) != 0) {
1449 /* Read rcvd_pad bits */
1450 if ((ret
= tsal_pcp_io_op(sc
, &rsvd_pad
, sizeof (rsvd_pad
),
1451 PCP_IO_OP_READ
)) != 0) {
1455 /* receive transaction id */
1456 if ((ret
= tsal_pcp_io_op(sc
, &xid
, sizeof (xid
),
1457 PCP_IO_OP_READ
)) != 0) {
1463 /* receive timeout value */
1464 if ((ret
= tsal_pcp_io_op(sc
, &timeout
, sizeof (timeout
),
1465 PCP_IO_OP_READ
)) != 0) {
1469 timeout
= ntohl(timeout
);
1471 /* receive message length */
1472 if ((ret
= tsal_pcp_io_op(sc
, &msg_len
, sizeof (msg_len
),
1473 PCP_IO_OP_READ
)) != 0) {
1477 msg_len
= ntohl(msg_len
);
1479 /* receive status field */
1480 if ((ret
= tsal_pcp_io_op(sc
, &status
, sizeof (status
),
1481 PCP_IO_OP_READ
)) != 0) {
1485 status
= ntohl(status
);
1487 /* receive message checksum */
1488 if ((ret
= tsal_pcp_io_op(sc
, &msg_cksum
, sizeof (msg_cksum
),
1489 PCP_IO_OP_READ
)) != 0) {
1493 msg_cksum
= ntohs(msg_cksum
);
1495 /* receive header checksum */
1496 if ((ret
= tsal_pcp_io_op(sc
, &hdr_cksum
, sizeof (hdr_cksum
),
1497 PCP_IO_OP_READ
)) != 0) {
1501 hdr_cksum
= ntohs(hdr_cksum
);
1503 /* copy to resp_hdr */
1505 resp_hdr
->magic_num
= magic_num
;
1506 resp_hdr
->proto_ver
= proto_ver
;
1507 resp_hdr
->msg_type
= msg_type
;
1508 resp_hdr
->sub_type
= sub_type
;
1509 resp_hdr
->rsvd_pad
= rsvd_pad
;
1510 resp_hdr
->xid
= xid
;
1511 resp_hdr
->timeout
= timeout
;
1512 resp_hdr
->msg_len
= msg_len
;
1513 resp_hdr
->status
= status
;
1514 resp_hdr
->msg_cksum
= msg_cksum
;
1515 resp_hdr
->hdr_cksum
= hdr_cksum
;
1517 return (TSAL_PCP_OK
);
1521 * Get next xid for including in request message.
1522 * Every request and response message are matched
1527 tsal_pcp_get_xid(tsalarm_softc_t
*sc
)
1530 static boolean_t xid_initialized
= B_FALSE
;
1532 if (xid_initialized
== B_FALSE
) {
1533 xid_initialized
= B_TRUE
;
1535 * starting xid is initialized to a different value everytime
1536 * user application is restarted so that user apps will not
1537 * receive previous session's packets.
1539 * Note: The algorithm for generating initial xid is partially
1540 * taken from Solaris rpc code.
1542 sc
->msg_xid
= (uint32_t)gethrtime();
1545 ret
= sc
->msg_xid
++;
1547 /* zero xid is not allowed */
1549 ret
= sc
->msg_xid
++;
1555 * This function handles channel framing errors. It waits until proper
1556 * frame with starting sequence as magic numder (0xAFBCAFA0)
1557 * is arrived. It removes unexpected data (before the magic number sequence)
1558 * on the channel. It returns when proper magic number sequence is seen
1559 * or when any failure happens while reading/peeking the channel.
1562 tsal_pcp_frame_error_handle(tsalarm_softc_t
*sc
)
1564 uint8_t magic_num_buf
[4];
1566 uint32_t net_magic_num
; /* magic byte in network byte order */
1567 uint32_t host_magic_num
= PCP_MAGIC_NUM
;
1570 net_magic_num
= htonl(host_magic_num
);
1571 (void) memcpy(magic_num_buf
, (uint8_t *)&net_magic_num
, 4);
1573 while (!ispresent
) {
1575 * Check if next four bytes matches pcp magic number.
1576 * if mathing not found, discard 1 byte and continue checking.
1578 if (!check_magic_byte_presence(sc
, 4, &magic_num_buf
[0],
1582 (void) tsal_pcp_io_op(sc
, buf
, 1,
1594 * checks whether certain byte sequence is present in the data stream.
1597 check_magic_byte_presence(tsalarm_softc_t
*sc
,
1598 int byte_cnt
, uint8_t *byte_seq
, int *ispresent
)
1603 if ((ret
= tsal_pcp_peek_read(sc
, buf
, byte_cnt
)) < 0) {
1607 /* 'byte_cnt' bytes not present */
1608 if (ret
!= byte_cnt
) {
1613 for (i
= 0; i
< byte_cnt
; ++i
) {
1614 if (buf
[i
] != byte_seq
[i
]) {
1625 * 16-bit simple internet checksum
1628 checksum(uint16_t *addr
, int32_t count
)
1631 * Compute Internet Checksum for "count" bytes
1632 * beginning at location "addr".
1635 register uint32_t sum
= 0;
1638 /* This is the inner loop */
1639 sum
+= *(unsigned short *)addr
++;
1643 /* Add left-over byte, if any */
1645 sum
+= * (unsigned char *)addr
;
1647 /* Fold 32-bit sum to 16 bits */
1649 sum
= (sum
& 0xffff) + (sum
>> 16);
1651 sum
= (~sum
) & 0xffff;